diff --git a/Gemfile.lock b/Gemfile.lock
index e2c04c0..7d656a9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,62 +1,100 @@
GEM
remote: https://rubygems.org/
specs:
- addressable (2.5.2)
- public_suffix (>= 2.0.2, < 4.0)
+ addressable (2.9.0)
+ public_suffix (>= 2.0.2, < 8.0)
+ base64 (0.3.0)
+ bigdecimal (3.2.2)
colorator (1.1.0)
- faraday (0.14.0)
- multipart-post (>= 1.2, < 3)
- ffi (1.9.21)
+ concurrent-ruby (1.3.5)
+ csv (3.3.5)
+ em-websocket (0.5.3)
+ eventmachine (>= 0.12.9)
+ http_parser.rb (~> 0)
+ eventmachine (1.2.7)
+ faraday (2.14.1)
+ faraday-net_http (>= 2.0, < 3.5)
+ json
+ logger
+ faraday-net_http (3.4.2)
+ net-http (~> 0.5)
+ ffi (1.17.2)
forwardable-extended (2.6.0)
- jekyll (3.6.2)
+ google-protobuf (4.31.1)
+ bigdecimal
+ rake (>= 13)
+ http_parser.rb (0.8.0)
+ i18n (1.14.7)
+ concurrent-ruby (~> 1.0)
+ jekyll (4.4.1)
addressable (~> 2.4)
+ base64 (~> 0.2)
colorator (~> 1.0)
- jekyll-sass-converter (~> 1.0)
- jekyll-watch (~> 1.1)
- kramdown (~> 1.14)
+ csv (~> 3.0)
+ em-websocket (~> 0.5)
+ i18n (~> 1.0)
+ jekyll-sass-converter (>= 2.0, < 4.0)
+ jekyll-watch (~> 2.0)
+ json (~> 2.6)
+ kramdown (~> 2.3, >= 2.3.1)
+ kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
- mercenary (~> 0.3.3)
+ mercenary (~> 0.3, >= 0.3.6)
pathutil (~> 0.9)
- rouge (>= 1.7, < 3)
+ rouge (>= 3.0, < 5.0)
safe_yaml (~> 1.0)
- jekyll-feed (0.9.2)
- jekyll (~> 3.3)
- jekyll-gist (1.4.1)
+ terminal-table (>= 1.8, < 4.0)
+ webrick (~> 1.7)
+ jekyll-feed (0.17.0)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-paginate (1.1.0)
- jekyll-redirect-from (0.13.0)
- jekyll (~> 3.3)
- jekyll-sass-converter (1.5.0)
- sass (~> 3.4)
- jekyll-sitemap (1.1.1)
- jekyll (~> 3.3)
- jekyll-watch (1.5.1)
+ jekyll-redirect-from (0.16.0)
+ jekyll (>= 3.3, < 5.0)
+ jekyll-sass-converter (3.1.0)
+ sass-embedded (~> 1.75)
+ jekyll-sitemap (1.4.0)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-watch (2.2.1)
listen (~> 3.0)
- kramdown (1.16.2)
- liquid (4.0.0)
- listen (3.0.6)
- rb-fsevent (>= 0.9.3)
- rb-inotify (>= 0.9.7)
- mercenary (0.3.6)
- multipart-post (2.0.0)
- octokit (4.8.0)
- sawyer (~> 0.8.0, >= 0.5.3)
- pathutil (0.16.1)
+ json (2.19.2)
+ kramdown (2.5.1)
+ rexml (>= 3.3.9)
+ kramdown-parser-gfm (1.1.0)
+ kramdown (~> 2.0)
+ liquid (4.0.4)
+ listen (3.9.0)
+ rb-fsevent (~> 0.10, >= 0.10.3)
+ rb-inotify (~> 0.9, >= 0.9.10)
+ logger (1.7.0)
+ mercenary (0.4.0)
+ net-http (0.9.1)
+ uri (>= 0.11.1)
+ octokit (4.25.1)
+ faraday (>= 1, < 3)
+ sawyer (~> 0.9)
+ pathutil (0.16.2)
forwardable-extended (~> 2.6)
- public_suffix (2.0.5)
- rb-fsevent (0.10.2)
- rb-inotify (0.9.10)
- ffi (>= 0.5.0, < 2)
- rouge (2.2.1)
- safe_yaml (1.0.4)
- sass (3.5.5)
- sass-listen (~> 4.0.0)
- sass-listen (4.0.0)
- rb-fsevent (~> 0.9, >= 0.9.4)
- rb-inotify (~> 0.9, >= 0.9.7)
- sawyer (0.8.1)
- addressable (>= 2.3.5, < 2.6)
- faraday (~> 0.8, < 1.0)
+ public_suffix (7.0.5)
+ rake (13.3.0)
+ rb-fsevent (0.11.2)
+ rb-inotify (0.11.1)
+ ffi (~> 1.0)
+ rexml (3.4.2)
+ rouge (4.5.2)
+ safe_yaml (1.0.5)
+ sass-embedded (1.89.2)
+ google-protobuf (~> 4.31)
+ rake (>= 13)
+ sawyer (0.9.2)
+ addressable (>= 2.3.5)
+ faraday (>= 0.17.3, < 3)
+ terminal-table (3.0.2)
+ unicode-display_width (>= 1.1.1, < 3)
+ unicode-display_width (2.6.0)
+ uri (1.1.1)
+ webrick (1.9.1)
PLATFORMS
ruby
@@ -70,4 +108,4 @@ DEPENDENCIES
jekyll-sitemap
BUNDLED WITH
- 1.16.1
+ 2.6.9
diff --git a/_layouts/post.html b/_layouts/post.html
index 7d6a247..7bc2ad6 100644
--- a/_layouts/post.html
+++ b/_layouts/post.html
@@ -19,7 +19,10 @@
output += "中文版";
} else if (languages[i] == "es") {
output += "Español";
+ } else if (languages[i] == "ja_jp") {
+ output += "日本語";
}
+
}
return output;
diff --git a/about.md b/about.md
index 0825c4d..c749748 100644
--- a/about.md
+++ b/about.md
@@ -31,4 +31,4 @@ Dwaraka Nath is a masters graduate from Birla Institute of Technology and Scienc
You can find more about him on his [personal website](https://www.dwarak.in) and follow him on GitHub at [@dtsdwarak](https://github.com/dtsdwarak).
### Wesley Bland
-Wesley Bland is a researcher in High Performance Computing and a contributor to both MPICH and Open MPI. He graduated from the University of Tennessee, Knoxville with his PhD under Dr. Jack Dongarra. His research involved fault tolerance at scale using MPI. After leaving the university, he went to Argonne National Laboratory where he worked under Dr. Pavan Balaji as a postdoctoral appointee and continued his fault tolerance research while working on MPICH directly. He currently works at Intel Corporation on high performance runtimes, including MPI.
+Wesley Bland is a researcher in High Performance Computing and a contributor to both MPICH and Open MPI. He graduated from the University of Tennessee, Knoxville with his PhD under Dr. Jack Dongarra. His research involved fault tolerance at scale using MPI. After leaving the university, he went to Argonne National Laboratory where he worked under Dr. Pavan Balaji as a postdoctoral appointee and continued his fault tolerance research while working on MPICH directly. He has also worked at Intel and Meta.
diff --git a/recommended-books.md b/recommended-books.md
index b37824a..6dd1208 100644
--- a/recommended-books.md
+++ b/recommended-books.md
@@ -12,8 +12,8 @@ My personal favorite MPI book. The book gives a good overview of parallel comput
[](http://www.amazon.com/gp/product/1558603395/ref=as_li_qf_sp_asin_il?ie=UTF8&linkCode=as2&camp=217145&creative=399377&creativeASIN=1558603395)
-## Using MPI - 3rd Edition
-This is a more up-to-date book than the previous, but it mostly focuses on the newer and more advanced MPI routines in the third MPI standard. These include parallel I/O, remote memory access, and dynamic process management. The book also discusses using MPI with threads. This is a must have for advanced MPI development. [Click here for more info](https://www.amazon.com/gp/product/0262527391/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0262527391&linkCode=as2&linkId=52cc270bc3a798b37c787740d00c19d1).
+## Using MPI - 3rd Edition and Using Advanced MPI - 1st Edition
+This is a more up-to-date book than the previous. The "regular" book covers the fundamentals of MPI and the "advnaced" book covers additional topics. The table of contents can be found on [this](https://www.mcs.anl.gov/research/projects/mpi/usingmpi/) website. This is a must have for advanced MPI development. [Click here for Using MPI](https://www.amazon.com/gp/product/0262527391/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0262527391&linkCode=as2&linkId=52cc270bc3a798b37c787740d00c19d1). The "Using Advanced MPI" book is currently out of print.
[](https://www.amazon.com/gp/product/0262527391/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0262527391&linkCode=as2&linkId=52cc270bc3a798b37c787740d00c19d1)
diff --git a/tutorials.md b/tutorials.md
index e477fbe..a80dd8d 100644
--- a/tutorials.md
+++ b/tutorials.md
@@ -9,24 +9,48 @@ Welcome to the MPI tutorials! In these tutorials, you will learn a wide array of
The tutorials assume that the reader has a basic knowledge of C, some C++, and Linux.
## Introduction and MPI installation
-* [MPI tutorial introduction]({{ site.baseurl }}/tutorials/mpi-introduction/) ([中文版]({{ site.baseurl }}/tutorials/mpi-introduction/zh_cn))
-* [Installing MPICH2 on a single machine]({{ site.baseurl }}/tutorials/installing-mpich2/) ([中文版]({{ site.baseurl }}/tutorials/installing-mpich2/zh_cn))
+* [MPI tutorial introduction]({{ site.baseurl }}/tutorials/mpi-introduction/)
+([中文版]({{ site.baseurl }}/tutorials/mpi-introduction/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/mpi-introduction/ja_jp))
+* [Installing MPICH2 on a single machine]({{ site.baseurl }}/tutorials/installing-mpich2/)
+([中文版]({{ site.baseurl }}/tutorials/installing-mpich2/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/installing-mpich2/ja_jp))
* [Launching an Amazon EC2 MPI cluster]({{ site.baseurl }}/tutorials/launching-an-amazon-ec2-mpi-cluster/)
+([日本語]({{ site.baseurl }}/tutorials/launching-an-amazon-ec2-mpi-cluster/ja_jp))
* [Running an MPI cluster within a LAN]({{ site.baseurl }}/tutorials/running-an-mpi-cluster-within-a-lan/)
-* [Running an MPI hello world application]({{ site.baseurl }}/tutorials/mpi-hello-world/) ([中文版]({{ site.baseurl }}/tutorials/mpi-hello-world/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/running-an-mpi-cluster-within-a-lan/ja_jp))
+* [Running an MPI hello world application]({{ site.baseurl }}/tutorials/mpi-hello-world/)
+([中文版]({{ site.baseurl }}/tutorials/mpi-hello-world/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/mpi-hello-world/ja_jp))
## Blocking point-to-point communication
-* [Sending and receiving with MPI_Send and MPI_Recv]({{ site.baseurl }}/tutorials/mpi-send-and-receive/) ([中文版]({{ site.baseurl }}/tutorials/mpi-send-and-receive/zh_cn))
-* [Dynamic receiving with MPI_Probe and MPI_Status]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/) ([中文版]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/zh_cn))
-* [Point-to-point communication application - Random walking]({{ site.baseurl }}/tutorials/point-to-point-communication-application-random-walk/) ([中文版]({{ site.baseurl }}/tutorials/point-to-point-communication-application-random-walk/zh_cn))
+* [Sending and receiving with MPI_Send and MPI_Recv]({{ site.baseurl }}/tutorials/mpi-send-and-receive/)
+([中文版]({{ site.baseurl }}/tutorials/mpi-send-and-receive/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/mpi-send-and-receive/ja_jp))
+* [Dynamic receiving with MPI_Probe and MPI_Status]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/)
+([中文版]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/ja_jp))
+* [Point-to-point communication application - Random walking]({{ site.baseurl }}/tutorials/point-to-point-communication-application-random-walk/)
+([中文版]({{ site.baseurl }}/tutorials/point-to-point-communication-application-random-walk/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/point-to-point-communication-application-random-walk/ja_jp))
## Basic collective communication
-* [Collective communication introduction with MPI_Bcast]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/) ([中文版]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/zh_cn))
-* [Common collectives - MPI_Scatter, MPI_Gather, and MPI_Allgather]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/) ([中文版]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/zh_cn))
-* [Application example - Performing parallel rank computation with basic collectives]({{ site.baseurl }}/tutorials/performing-parallel-rank-with-mpi/) ([中文版]({{ site.baseurl }}/tutorials/performing-parallel-rank-with-mpi/zh_cn))
+* [Collective communication introduction with MPI_Bcast]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/)
+([中文版]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/ja_jp))
+* [Common collectives - MPI_Scatter, MPI_Gather, and MPI_Allgather]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/)
+([中文版]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/ja_jp))
+* [Application example - Performing parallel rank computation with basic collectives]({{ site.baseurl }}/tutorials/performing-parallel-rank-with-mpi/)
+([中文版]({{ site.baseurl }}/tutorials/performing-parallel-rank-with-mpi/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/performing-parallel-rank-with-mpi/ja_jp))
## Advanced collective communication
-* [Using MPI_Reduce and MPI_Allreduce for parallel number reduction]({{ site.baseurl }}/tutorials/mpi-reduce-and-allreduce/) ([中文版]({{ site.baseurl }}/tutorials/mpi-reduce-and-allreduce/zh_cn))
+* [Using MPI_Reduce and MPI_Allreduce for parallel number reduction]({{ site.baseurl }}/tutorials/mpi-reduce-and-allreduce/)
+([中文版]({{ site.baseurl }}/tutorials/mpi-reduce-and-allreduce/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/mpi-reduce-and-allreduce/ja_jp))
## Groups and communicators
-* [Introduction to groups and communicators]({{ site.baseurl }}/tutorials/introduction-to-groups-and-communicators/) ([中文版]({{ site.baseurl }}/tutorials/introduction-to-groups-and-communicators/zh_cn))
+* [Introduction to groups and communicators]({{ site.baseurl }}/tutorials/introduction-to-groups-and-communicators/)
+([中文版]({{ site.baseurl }}/tutorials/introduction-to-groups-and-communicators/zh_cn))
+([日本語]({{ site.baseurl }}/tutorials/introduction-to-groups-and-communicators/ja_jp))
diff --git a/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/index.md b/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/index.md
index 2cff7a3..82af8aa 100644
--- a/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/index.md
+++ b/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/index.md
@@ -4,7 +4,7 @@ title: Dynamic Receiving with MPI Probe (and MPI Status)
author: Wes Kendall
categories: Beginner MPI
tags: MPI_Get_count, MPI_Probe
-translations: zh_cn
+translations: zh_cn,ja_jp
redirect_from: '/dynamic-receiving-with-mpi-probe-and-mpi-status/'
---
diff --git a/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/ja_jp.md b/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/ja_jp.md
new file mode 100644
index 0000000..e551213
--- /dev/null
+++ b/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/ja_jp.md
@@ -0,0 +1,141 @@
+---
+layout: post
+title: MPI Probeを用いた可変長メッセージの受信 - Dynamic Receiving with MPI Probe (and MPI Status)
+author: Wes Kendall
+categories: Beginner MPI
+tags: MPI_Get_count, MPI_Probe
+redirect_from: '/dynamic-receiving-with-mpi-probe-and-mpi-status/'
+---
+
+[前回のレッスン]({{ site.baseurl }}/tutorials/mpi-send-and-receive/)ではMPI_SendとMPI_Recvを使用した基本的なポイントツーポイント通信を学びました。前回はメッセージ長が固定である場合のみを説明しました。可変長メッセージを送る方法として1つ目のメッセージ長をsend/recvするという方法もとれます。しかし、MPIには追加の関数呼び出しだけで可変長のメッセージをサポートすることが可能です。このレッスンではこの方法を学びます。
+
+> **Note** - このサイトのコードはすべて[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは[tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/code]({{ site.github.code }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/code)にあります。
+
+## MPI_Status構造体 - The MPI_Status structure
+[前回のレッスン]({{ site.baseurl }}/tutorials/mpi-send-and-receive/)で説明したように、`MPI_Recv`は受信したメッセージに関する情報を`MPI_Status`として受け取ります(`MPI_STATUS_IGNORE`で無視することもできます)。`MPI_Recv`関数に`MPI_Status`を渡していると受信操作が完了した後に次の3つの追加情報を得ることができます。
+
+1. **送信者のランク**: 送信者のランクは`MPI_SOURCE`構造体に格納されます。`MPI_Status stat`と宣言すると、ランクには`stat.MPI_SOURCE`でアクセスできます。
+2. **メッセージタグ**: メッセージのタグは`MPI_TAG`に格納されます。`MPI_SOURCE`と同じようにアクセスできます。
+3. **メッセージ長**: メッセージ長は、ステータス構造内には含まれません。そこで`MPI_Get_count`を使用してメッセージの長さを調べる必要があります。
+
+```cpp
+MPI_Get_count(
+ MPI_Status* status,
+ MPI_Datatype datatype,
+ int* count)
+```
+
+`MPI_Get_count`関数に`MPI_Status`渡すとメッセージの`datatype`と`count`が返されます。`count`には受信した要素の合計数が入ります。
+
+なぜこの2つの情報が必要になるのかを説明します。`MPI_Recv`受信のために`MPI_ANY_SOURCE`を送信者のランクに、`MPI_ANY_TAG`をメッセージのタグとして受信動作を行えます。この場合には`MPI_Status`が送信者とメッセージタグを知る唯一の手がかりになります(訳注:rankとtagを指定してrecvしていない場合、という意味です。)。また、`MPI_Recv`関数は引数として指定した要素数を全て受信することが保証されていないことに注意します。受信した要素数を得ることができます。しかしながら、指定した受信できる数以上の要素が送信された場合はエラーになることに注意してください。`MPI_Get_count`は実際に受信する量を決定するのに使われます。
+
+## MPI_Status構造体をクエリする例 - An example of querying the MPI_Status structure
+
+`MPI_Status`構造体をクエリするプログラム[check_status.c]({{ site.github.code }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/code/check_status.c)を見ていきます。プログラムは数字を適当な個数送信します。受信者は送信された数字の数を調べます。コードのメイン部分は次のようになります。
+
+```cpp
+const int MAX_NUMBERS = 100;
+int numbers[MAX_NUMBERS];
+int number_amount;
+if (world_rank == 0) {
+ // プロセス1に送る数字の数を決定する
+ srand(time(NULL));
+ number_amount = (rand() / (float)RAND_MAX) * MAX_NUMBERS;
+
+ // その分の数をプロセス1に送る
+ MPI_Send(numbers, number_amount, MPI_INT, 1, 0, MPI_COMM_WORLD);
+ printf("0 sent %d numbers to 1\n", number_amount);
+} else if (world_rank == 1) {
+ MPI_Status status;
+ // 最大でMAX_NUMBERS個のMPI_INTをプロセス0から受け取る
+ MPI_Recv(numbers, MAX_NUMBERS, MPI_INT, 0, 0, MPI_COMM_WORLD,
+ &status);
+
+ // メッセージを受信した後、そのメッセージにいくつの整数が含まれていたかを
+ // 取得する
+ MPI_Get_count(&status, MPI_INT, &number_amount);
+
+ // 含まれていた数字の数、ランク、タグを出力する。
+ printf("1 received %d numbers from 0. Message source = %d, "
+ "tag = %d\n",
+ number_amount, status.MPI_SOURCE, status.MPI_TAG);
+}
+```
+
+プロセス0は最大で`MAX_NUMBERS`個の整数をランダムに決めてプロセス1に送信します。プロセス1は最大で`MAX_NUMBERS`個の整数を読み込む`MPI_Recv`を実行します。プロセス1は`MPI_Recv` の引数として `MAX_NUMBERS` を渡しています。繰り返しになりますが、プロセス1が受け取ることができるのは**最大**この個数であることに注意してください。プロセス1では`MPI_Get_count`を呼び出して、実際に受信した`MPI_INT`の数をを調べます。プロセス1は受信したメッセージのサイズを表示すると同時に、`MPI_SOURCE`と`MPI_TAG`、つまり送信元ランクとタグも表示します。
+
+ここで注意があります。`MPI_Get_count`で得られるのはデータ型の数でバイト数でないことです。もしユーザーが`MPI_CHAR`をデータ型として(recvを)使用したとすると、返されるデータ量は4倍になります(intを4バイト、charを1バイトと仮定した場合)。このプログラムを[レポジトリ]({{ site.github.code }})の*tutorials*ディレクトリから実行すると、出力はこのようになるでしょう。
+
+```
+>>> cd tutorials
+>>> ./run.py check_status
+mpirun -n 2 ./check_status
+0 sent 92 numbers to 1
+1 received 92 numbers from 0. Message source = 0, tag = 0
+```
+
+プロセス0はプロセス1にランダムな数の整数を送信して、プロセス1は受信したメッセージに関する情報を出力できました。
+
+## MPI_Probeを使用してメッセージサイズを調べる - Using MPI_Probe to find out the message size
+`MPI_Status`への理解が深まってきました。前回の例では受信前にすべてのサイズのメッセージを処理できるように大きなバッファを用意しました。実は、`MPI_Probe`を使用すると受信前にメッセージ長を調べることができます。
+
+```cpp
+MPI_Probe(
+ int source,
+ int tag,
+ MPI_Comm comm,
+ MPI_Status* status)
+```
+
+`MPI_Probe`は`MPI_Recv`と似た呼び出しです。`MPI_Probe`は`MPI_Recv`で実際に受信する以外の処理を行うと考えて良いです。`MPI_Recv`と同様に`MPI_Probe`は指定したタグかつ指定した送信者ランクであるメッセージが来るまでブロッキングします。メッセージを受信するとstatus構造体に情報が格納されます。その後にユーザは(そのデータを受信するのに十分なバッファを用意して)`MPI_Recv`で実際にメッセージを受信すれば良いのです。
+
+[レポジトリ]({{ site.github.code }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/code/code)の[probe.c]({{ site.github.code }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/code/probe.c)にこの例を示します。
+
+```cpp
+int number_amount;
+if (world_rank == 0) {
+ const int MAX_NUMBERS = 100;
+ int numbers[MAX_NUMBERS];
+ // プロセス1に送る数字の数を決定する
+ srand(time(NULL));
+ number_amount = (rand() / (float)RAND_MAX) * MAX_NUMBERS;
+
+ // その分の数をプロセス1に送る
+ MPI_Send(numbers, number_amount, MPI_INT, 1, 0, MPI_COMM_WORLD);
+ printf("0 sent %d numbers to 1\n", number_amount);
+} else if (world_rank == 1) {
+ MPI_Status status;
+ // プロセス0からのメッセージを"probe"する
+ MPI_Probe(0, 0, MPI_COMM_WORLD, &status);
+
+ // probeが完了した時、statusにはメッセージ長などの情報が含まれている
+ // MPI_Get_countを使ってメッセージ長を得る
+ MPI_Get_count(&status, MPI_INT, &number_amount);
+
+ // probeで判明したメッセージ長文のメモリを確保する
+ int* number_buf = (int*)malloc(sizeof(int) * number_amount);
+
+ // そのバッファを使用してrecv処理を行う
+ MPI_Recv(number_buf, number_amount, MPI_INT, 0, 0,
+ MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+ printf("1 dynamically received %d numbers from 0.\n",
+ number_amount);
+ free(number_buf);
+}
+```
+
+先程の例と同様、プロセス0はプロセス1に送信する変数の数をランダムに決定します。変更点は、プロセス1が `MPI_Probe`を呼び出してプロセス0が送信しようとしている要素の数を(`MPI_Get_count`を使用して)得ることです。この後、プロセス1が適切なサイズのバッファを確保してから数値を受信します。
+
+```
+>>> ./run.py probe
+mpirun -n 2 ./probe
+0 sent 93 numbers to 1
+1 dynamically received 93 numbers from 0
+```
+
+ここで示した例はシンプルなものです。`MPI_Probe`は多くのMPIアプリケーションで用いられる基本的な機能です。例えばマネージャ/ワーカプログラムは、可変サイズのメッセージを交換する際に`MPI_Probe`を多用します。練習として、`MPI_Probe`を使用した`MPI_Recv`のラッパーを作成し、動的なアプリケーションを書いてみてください。コードの見栄えが格段に良くなるでしょう :-)
+
+## Up next
+さて、標準的なブロック型ポイント・ツー・ポイント通信に抵抗はなくなってきましたか?そうなら、あなたはすでにいくらでも並列アプリケーションを書く能力を持っています!では、学んだルーチンを使ったより高度な例を見てみましょう。[the application example using MPI_Send, MPI_Recv, and MPI_Probe]({{ site.baseurl }}/tutorials/point-to-point-communication-application-random-walk/) をチェックしてください。
+
+困っていますか?混乱していますか?お気軽に下記にコメントを残してください。私や他の読者がお役に立てるかもしれません。
diff --git a/tutorials/installing-mpich2/index.md b/tutorials/installing-mpich2/index.md
index c368782..92e032e 100644
--- a/tutorials/installing-mpich2/index.md
+++ b/tutorials/installing-mpich2/index.md
@@ -4,7 +4,7 @@ title: Installing MPICH2 on a Single Machine
author: Wes Kendall
categories: Beginner MPI
tags:
-translations: zh_cn
+translations: zh_cn,ja_jp
redirect_from: '/installing-mpich2/'
---
@@ -13,11 +13,11 @@ MPI is simply a standard which others follow in their implementation. Because of
MPICH is a widely-used implementation of MPI that is developed primarily by Argonne National Laboratory in the United States. The main reason for choosing MPICH over other implementations is simply because of my familiarity with the interface and because of my close relationship with Argonne National Laboratory. I also encourage others to check out [OpenMPI](https://www.open-mpi.org/), which is also a widely-used implementation.
## Installing MPICH
-The latest version of MPICH is available [here](https://www.mpich.org/). The version that I will be using for all of the examples on the site is 3.3-2, which was released 13 November 2019. Go ahead and download the source code, uncompress the folder, and change into the MPICH3 directory.
+The latest version of MPICH is available [here](https://www.mpich.org/). The version that I will be using for all of the examples on the site is 3.3-2, which was released 13 November 2019. Go ahead and download the source code, uncompress the folder, and change into the MPICH directory.
```
->>> tar -xzf mpich3-3.2.tar.gz
->>> cd mpich3-3.2
+>>> tar -xzf mpich-3-3.2.tar.gz
+>>> cd mpich-3-3.2
```
Once doing this, you should be able to configure your installation by performing `./configure`. If you need to install MPICH to a local directory (for example, if you don't have root access to your machine), type `./configure --prefix=/installation/directory/path`. It is possible to avoid building the MPI Fortran library by using `./configure --disable-fortran` if you do not have Fortran compilers. For more information about possible configuration parameters, type `./configure --help`
diff --git a/tutorials/installing-mpich2/ja_jp.md b/tutorials/installing-mpich2/ja_jp.md
new file mode 100644
index 0000000..e73efc5
--- /dev/null
+++ b/tutorials/installing-mpich2/ja_jp.md
@@ -0,0 +1,55 @@
+---
+layout: post
+title: MPIをシングルマシンにインストールする - Installing MPICH2 on a Single Machine
+author: Wes Kendall
+categories: Beginner MPI
+tags:
+redirect_from: '/installing-mpich2/'
+---
+
+MPIとは標準仕様を指すものであるのでMPIの実装は複数存在します。このレッスンでは主な実装の1つであるMPICHを使用します。あなたが望むなら他の実装を使用しても良いですが、このレッスンではMPICHインストール手順を紹介します。また、チュートリアル全体で提供されるスクリプトとコードは、最新バージョンのMPICHでの実行だけを確認しています。
+
+MPICHは米国のアルゴンヌ国立研究所が主に開発したメジャーなMPI実装です。MPICHを選択した理由は、私がこのインターフェイスに精通しておりアルゴンヌ国立研究所と縁が深いためです。広く使用されている実装である[OpenMPI](https://www.open-mpi.org/)もぜひ調べてみてください。
+
+## MPICHのインストール - Installing MPICH
+[ここ](https://www.mpich.org/)からMPICHの最新バージョンを入手できます。このチュートリアルでは3.3-2(2019年11月13日リリース)を利用します。tar.gzファイルをダウンロードし以下のように伸長します。
+
+```
+>>> tar -xzf mpich-3-3.2.tar.gz
+>>> cd mpich-3-3.2
+```
+
+`./configure`でmakeの準備をします。この際にマシンの特権がなくユーザディレクトリにインストールしたい場合は`./configure --prefix=/installation/directory/path`としてインストールディレクトリを指定できます。Fortranへの対応が不要である場合は`./configure --disable-fortran`とします。利用可能なオプションを全て表示するには`./configure --help`とします。
+
+```
+>>> ./configure
+Configuring MPICH version 3.3.2
+Running on system: Linux localhost.localdomain 5.8.18-100.fc31.x86_64 #1 SMP Mon Nov 2 20:32:55 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
+checking build system type... x86_64-unknown-linux-gnu
+```
+
+configureが終了して*"Configuration completed."*と表示さたら`make; sudo make install`を使用して MPICH2 をビルド・インストールします。
+```
+>>> make; sudo make install
+make
+make all-recursive
+
+```
+
+成功したなら`mpiexec --version`でインストールした情報を出力できます。
+
+```
+>>> mpiexec --version
+HYDRA build details:
+ Version: 3.3.2
+ Release Date: Tue Nov 12 21:23:16 CST 2019
+ CC: gcc
+ CXX: g++
+ F77: gfortran
+ F90: gfortran
+```
+
+皆さんの環境でもビルドが無事に完了することを祈りますが、依存関係不足などで問題が起こる可能性があるでしょう。このような場合はエラーメッセージをGoogleで検索してみてください。
+
+## 次は?
+単一の環境にMPICHを構築できたのでこのサイトで次に進むための選択肢がいくつかあります。ローカルクラスタをセットアップするためのハードウェアとリソースがすでにある場合は、[running an MPI cluster in LAN]({{ site.baseurl }}/tutorials/running-an-mpi-cluster-within-a-lan)に進むことを推奨します。そのようなクラスタにアクセスできない場合や仮想 MPIクラスターの構築について詳しく知りたい場合は、[building and running your own cluster on Amazon EC2]({{ site.baseurl }}/tutorials/launching-an-amazon-ec2-mpi-cluster/)に進んでください。いずれかの方法でクラスターを構築し終わっていたり、残りのレッスンをスタンドアロンで実行する場合は[MPI hello world lesson]({{ site.baseurl }}/tutorials/mpi-hello-world/)に進んでください。Hello Worldではプログラミングの基礎と最初のMPIプログラムの実行の概要が説明されています。
\ No newline at end of file
diff --git a/tutorials/introduction-to-groups-and-communicators/code/groups.c b/tutorials/introduction-to-groups-and-communicators/code/comm_groups.c
similarity index 100%
rename from tutorials/introduction-to-groups-and-communicators/code/groups.c
rename to tutorials/introduction-to-groups-and-communicators/code/comm_groups.c
diff --git a/tutorials/introduction-to-groups-and-communicators/code/split.c b/tutorials/introduction-to-groups-and-communicators/code/comm_split.c
similarity index 100%
rename from tutorials/introduction-to-groups-and-communicators/code/split.c
rename to tutorials/introduction-to-groups-and-communicators/code/comm_split.c
diff --git a/tutorials/introduction-to-groups-and-communicators/code/makefile b/tutorials/introduction-to-groups-and-communicators/code/makefile
index 60887ac..6ecc3dc 100644
--- a/tutorials/introduction-to-groups-and-communicators/code/makefile
+++ b/tutorials/introduction-to-groups-and-communicators/code/makefile
@@ -1,13 +1,13 @@
-EXECS=groups split
+EXECS=comm_groups comm_split
MPICC?=mpicc
all: ${EXECS}
-split: split.c
- ${MPICC} -o split split.c
+split: comm_split.c
+ ${MPICC} -o comm_split comm_split.c
-groups: groups.c
- ${MPICC} -o groups groups.c
+groups: comm_groups.c
+ ${MPICC} -o comm_groups comm_groups.c
clean:
rm -f ${EXECS}
diff --git a/tutorials/introduction-to-groups-and-communicators/index.md b/tutorials/introduction-to-groups-and-communicators/index.md
index 5290f7a..5fd6456 100644
--- a/tutorials/introduction-to-groups-and-communicators/index.md
+++ b/tutorials/introduction-to-groups-and-communicators/index.md
@@ -3,7 +3,7 @@ layout: post
title: Introduction to Groups and Communicators
author: Wesley Bland
categories: Advanced MPI
-translations: zh_cn
+translations: zh_cn,ja_jp
tags: MPI_Group, MPI_Comm
redirect_from: '/introduction-to-groups-and-communicators/'
---
diff --git a/tutorials/introduction-to-groups-and-communicators/ja_jp.md b/tutorials/introduction-to-groups-and-communicators/ja_jp.md
new file mode 100644
index 0000000..e777b3b
--- /dev/null
+++ b/tutorials/introduction-to-groups-and-communicators/ja_jp.md
@@ -0,0 +1,217 @@
+---
+layout: post
+title: グループとコミュニケータ - Introduction to Groups and Communicators
+author: Wesley Bland
+categories: Advanced MPI
+tags: MPI_Group, MPI_Comm
+redirect_from: '/introduction-to-groups-and-communicators/'
+---
+
+これまでのレッスンでは`MPI_COMM_WORLD`を使用してきました。単純なプログラムの場合はプロセスの数は多くないので、一度に1つのプロセスと話すか、一度に全てのプロセスと話すかでしょうから問題はありませんでした。しかし、プログラムの規模が大きくなり始めると、限定的なプロセスとしか通信をしたくないケースが出てきます。このレッスンでは、元となるプロセスグループの集合のプロセスとだけ集団通信するために、新しいコミュニケータを作成する方法を紹介します。
+
+> **Note** - チュートリアルのコードは[GitHub]({{ site.github.repo }})にあります。. このレッスンのコードは[tutorials/introduction-to-groups-and-communicators/code]({{ site.github.code }}/tutorials/introduction-to-groups-and-communicators/code)を参照してください。
+
+## コミュニケータとは? - Overview of communicators
+集団通信のレッスンで見てきたように、MPIの集団通信はコミュニケータ内の全プロセスと一度に通信できます。`MPI_Scatter`は他のプロセスにデータを分配したり、`MPI_Reduce`ではreduceを実行できます。しかし、これまではデフォルトの `MPI_COMM_WORLD` しか使ってきませんでした。
+
+単純なアプリケーションでは`MPI_COMM_WORLD`を使うことも珍しくないのですが、複雑なユースケースでは多くのコミュニケータがあった方が便利でしょう。例えば、グリッド内だけのプロセスのサブセットに対して計算を行いたい場合です。例として、各行の全プロセスの合計値を求めるような場合です。新しいコミュニケータを作成するための関数宣言を見てみましょう。
+
+
+```cpp
+MPI_Comm_split(
+ MPI_Comm comm,
+ int color,
+ int key,
+ MPI_Comm* newcomm)
+```
+
+`MPI_Comm_split`の名のとおり`color`と`key`に基づいて、あるコミュニケータをサブコミュニケータ群に"分割"して新しいコミュニケータを生成します。元のコミュニケータはなくならず、各プロセスに新しいコミュニケータが作成されることに注意してください。最初の引数`comm`は分割元のコミュニケータです。`MPI_COMM_WORLD`でもよいですし、他のコミュニケータでもかまいません。2番目の引数`color`は各プロセスがどの新しいコミュニケータに属するかを決定します。`color`に同じ値を渡したプロセスはすべて同じコミュニケータに割り当てられます。もし`color`が`MPI_UNDEFINED`であれば、そのプロセスは新しいコミュニケータには含まれません。3番目の引数`key`は、新しいコミュニケータ内の順序(ランク)を決定します。`key`の値が最も小さいプロセスがランク0になり、次に小さいプロセスがランク1になります。同順位の場合は、元のコミュニケーター内の順位が低いプロセスが最初になります。最後の引数`newcomm`は新しいコミュニケータです。
+
+## 複数のコミュニケータを使用する例 - Example of using multiple communicators
+
+単純な例として、1つのグローバルコミュニケータを複数のコミュニケータに分割してみます。元のコミュニケータには16個のプロセス存在しますが、これを4x4のグリッドに論理的にレイアウトし、グリッドを行ごとに分割したいというシナリオを考えます。それぞれの行にcolorをつけます。下の画像では左側の同じ色のプロセスグループが右側のそれぞれのコミュニケータに入る様子を示します。
+
+
+
+これを実現するコードです。
+
+```cpp
+// 元のコミュニケータのランクとサイズを得る
+int world_rank, world_size;
+MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
+MPI_Comm_size(MPI_COMM_WORLD, &world_size);
+
+int color = world_rank / 4; // 行をcolorとして使います
+
+// colorと元のランクを利用して新しいコミュニケータを作成します
+MPI_Comm row_comm;
+MPI_Comm_split(MPI_COMM_WORLD, color, world_rank, &row_comm);
+
+int row_rank, row_size;
+MPI_Comm_rank(row_comm, &row_rank);
+MPI_Comm_size(row_comm, &row_size);
+
+printf("WORLD RANK/SIZE: %d/%d \t ROW RANK/SIZE: %d/%d\n",
+ world_rank, world_size, row_rank, row_size);
+
+MPI_Comm_free(&row_comm);
+```
+
+まず、オリジナルのコミュニケータ`MPI_COMM_WORLD`の中での自分のランクとこのコミュニケータのサイズを得ます。次はローカルプロセスの "色(color) "を決定する大切な操作です。色によって、分割後のプロセスがどのコミュニケータに属するかが決定します。そして分割を実施します。ここで注目して欲しいのは分割操作のキーとして元のランク(`world_rank`)を使っていることです。新しいコミュニケーター内のすべてのプロセスは元のコミュニケーターと同じ順序としたいので、元のランクの値を使用します。分割後に新しいコミュニケータのサイズと自分のランクを表示します。
+
+```
+WORLD RANK/SIZE: 0/16 ROW RANK/SIZE: 0/4
+WORLD RANK/SIZE: 1/16 ROW RANK/SIZE: 1/4
+WORLD RANK/SIZE: 2/16 ROW RANK/SIZE: 2/4
+WORLD RANK/SIZE: 3/16 ROW RANK/SIZE: 3/4
+WORLD RANK/SIZE: 4/16 ROW RANK/SIZE: 0/4
+WORLD RANK/SIZE: 5/16 ROW RANK/SIZE: 1/4
+WORLD RANK/SIZE: 6/16 ROW RANK/SIZE: 2/4
+WORLD RANK/SIZE: 7/16 ROW RANK/SIZE: 3/4
+WORLD RANK/SIZE: 8/16 ROW RANK/SIZE: 0/4
+WORLD RANK/SIZE: 9/16 ROW RANK/SIZE: 1/4
+WORLD RANK/SIZE: 10/16 ROW RANK/SIZE: 2/4
+WORLD RANK/SIZE: 11/16 ROW RANK/SIZE: 3/4
+WORLD RANK/SIZE: 12/16 ROW RANK/SIZE: 0/4
+WORLD RANK/SIZE: 13/16 ROW RANK/SIZE: 1/4
+WORLD RANK/SIZE: 14/16 ROW RANK/SIZE: 2/4
+WORLD RANK/SIZE: 15/16 ROW RANK/SIZE: 3/4
+```
+
+出力順序が違っても心配しないでください。MPIプログラムで出力する場合、各プロセスはMPIジョブを起動した場所に出力を送り返さないと画面に出力されないからです。この例では見栄え良くするために並び替えています。
+
+最後に`MPI_Comm_free`でコミュニケータを解放することを忘れないでください。これは重要なステップではないように思うかもしれませんが、メモリを使い終わったら解放するのと同じくらい重要です。MPIオブジェクトが使われなくなったら、後で再利用できるように解放しなければなりません。MPIが一度に生成できるオブジェクトの数には限りがあるので、オブジェクトを解放しておかないとMPIが割り当て可能なオブジェクトを使い果たしたときに実行時エラーになる可能性があります。
+
+## その他のコミュニケータ作成機能 - Other communicator creation functions
+
+`MPI_Comm_split`は最も基本的なコミュニケータ作成関数ですが、他にも多くの関数があります。`MPI_Comm_dup`はコミュニケータを複製します。複製だけを行う関数が必要か?と思われるかもしれませんがライブラリを実現するために非常に便利です。なぜなら、自分のコードとライブラリーのコードが互いに干渉しないようにしなければならないからです。ですから、アプリケーションが最初に行うべきことは`MPI_COMM_WORLD`の複製を作成することです。ライブラリ自身も`MPI_COMM_WORLD`を複製して使うべきです。
+
+もう一つの関数は`MPI_Comm_create`です。この関数は (後述する)`MPI_Comm_create_group` とよく似ています。
+
+```cpp
+MPI_Comm_create(
+ MPI_Comm comm,
+ MPI_Group group,
+ MPI_Comm* newcomm)
+```
+
+最も大きな違いは`MPI_Comm_create`が`comm`に含まれる全てのプロセスを集団として扱うのに対して、 (後述する)`MPI_Comm_create_group` は `group` に含まれるプロセス群だけを対象とします。これはコミュニケータのサイズが非常に大きい時に大切になります。`MPI_COMM_WORLD` のサブセットを1,000,000プロセスで実行する場合、サイズが大きくなると集団通信は非常に高価なコストとなるため、少ないプロセスで処理を実行することが重要になってくるのです。
+
+インターコミュニケータとイントラコミュニケータの違い、その他の高度なコミュニケータ作成関数などは今回のチュートリアルでは取り上げません。しかし、コミュニケータには他にも高度な機能があります。これらは特殊なアプリケーションでのみ使用されるものです。将来のチュートリアルで取り上げるかもしれません。
+
+## グループの概要 - Overview of groups
+
+`MPI_Comm_split` は新しいコミュニケータを作成する最も簡単な方法ですが他にもコミュニケータを作る方法はあります。それは`MPI_Group`という新しい種類のMPIオブジェクトを使う方法です。グループについて詳しく説明する前に、コミュニケータとは何かもう少し説明します。MPI内部的にはコミュニケータを構成する2つの主要な情報、コミュニケータと他のコミュニケータを区別するコンテキスト(context)またはIDと、コミュニケータに含まれるプロセスのグループを管理しています。コンテキストは、あるコミュニケータ上の操作が他のコミュニケータの操作に影響しないようにするためのものです。このためにMPIは内部で各コミュニケータのIDを保持しています。グループとはそのコミュニケータに含まれるすべてのプロセスの集合のことです。これまで使ってきた`MPI_COMM_WORLD`とは`mpiexec`で起動されたすべてのプロセスです。他のコミュニケータはグループが異なります。上のコード例では`MPI_Comm_split`に同じ`color`にしたすべてのプロセスは同じグループになっています。
+
+MPIは集合論(set theory)で扱われる操作をグループに適応することができます。集合論をすべて理解する必要はありませんが2つの操作の意味を知っておいてください。ここでは"集合(set)"と呼ぶ代わりに、MPIに適用される "グループ(group)"という用語を使用します。まず、和集合(union)演算は2つの集合から新しい(潜在的に)大きな集合を作ります。この新しい集合には2つの集合のすべてのメンバが含まれます(重複はありません)。次に、積集合(intersection)は、他の二つの集合から新しい(潜在的に)小さい集合を作ります。この新しい集合には、元の集合の両方に存在するメンバがすべて含まれます。これら両方の操作の例を以下に図解で示します。
+
+
+
+上段の例は`{0, 1, 2, 3}` と `{2, 3, 4, 5}` の和集合は `{0, 1, 2, 3, 4, 5}` となります。2つ目の例では、`{0, 1, 2, 3}` と `{2, 3, 4, 5}` の積集合は `{2, 3}` となります。
+
+## グループの使用 - Using MPI groups
+
+グループの仕組みの基本がわかったので実際のMPI操作でどう使うのかをみていきます。MPIでは`MPI_Comm_group`ルーチンでコミュニケータ内のプロセスのグループを簡単に取得することができます。
+
+```cpp
+MPI_Comm_group(
+ MPI_Comm comm,
+ MPI_Group* group)
+```
+
+コミュニケータにはコンテキスト(ID)とグループが含まれます。`MPI_Comm_group` はそのグループオブジェクトへの参照を得ます。グループオブジェクトはコミュニケータオブジェクトと同じように動作しますが、集団通信ルーチンの引数としで他のランクと通信するためには使用できません(コンテキストが付加されていないためです)。ただし、グループのランクとサイズを取得することはできます (`MPI_Group_rank` と `MPI_Group_size`)。コミュニケーターではできずにグループだけができることとは、ローカルで新しいグループを作成することです。ここで注目するのはローカル操作とリモート操作の違いに注意してください。リモート操作では他のランクと通信が発生しますが、ローカル操作では通信は発生しません。新しいコミュニケーターを作成する場合はそのアプリケーション内のすべてのプロセスで同じコンテキストとグループを決定する必要があるためリモート操作となります。しかし、グループを作成する場合は各プロセスで同じコンテキストを持つ必要がないため通信する必要はなくローカル操作となります。このため通信を気にする必要はなくなります。
+
+グループに対する操作はとても簡単です。
+
+```cpp
+MPI_Group_union(
+ MPI_Group group1,
+ MPI_Group group2,
+ MPI_Group* newgroup)
+```
+
+積集合もみてみましょう。
+
+```cpp
+MPI_Group_intersection(
+ MPI_Group group1,
+ MPI_Group group2,
+ MPI_Group* newgroup)
+```
+
+どちらの演算も、操作は`group1`と`group2`に対して行われて、結果は`newgroup`に格納されます。
+
+MPI におけるグループの使い方はたくさんあります。グループが同じかどうかを比較する、あるグループから別のグループを引く、あるグループから特定のランクを除外する、あるグループのランクを別のグループに変換する、といったようにグループを使用することができます。最近MPIに追加された関数の中で最も役に立つのは`MPI_Comm_create_group`でしょう。これは新しいコミュニケータを作成する関数ですが `MPI_Comm_split` のようにその場で計算をして構成を決めるのではなく、 `MPI_Group`を受け取り、グループと同じプロセスをすべて持つ新しいコミュニケータを作成します。
+
+```cpp
+MPI_Comm_create_group(
+ MPI_Comm comm,
+ MPI_Group group,
+ int tag,
+ MPI_Comm* newcomm)
+```
+
+## グループの使用例 - Example of using groups
+
+グループの使い方の簡単な例です。`MPI_Group_incl`という関数を使ってグループ内の特定のランクを選択し、そのランクのみを含む新しいグループを作成します。
+
+```cpp
+MPI_Group_incl(
+ MPI_Group group,
+ int n,
+ const int ranks[],
+ MPI_Group* newgroup)
+```
+
+この関数は`group`に含まれるプロセスのうち、`ranks`に含まれるランクを持つプロセスのだけが`newgroup`に入ります。どのように機能するかを確かめるため、`MPI_COMM_WORLD`の素数のランクを含むコミュニケータを作成してみます。(訳注:素数は静的に与えています)
+
+```cpp
+// 元のコミュニケータのサイズとその中でのランクを取得
+int world_rank, world_size;
+MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
+MPI_Comm_size(MPI_COMM_WORLD, &world_size);
+
+// このプロセスのMPI_COMM_WORLD内でのグループを得る
+MPI_Group world_group;
+MPI_Comm_group(MPI_COMM_WORLD, &world_group);
+
+int n = 7;
+const int ranks[7] = {1, 2, 3, 5, 7, 11, 13};
+
+// world_groupで素数ランクを持つプロセスだけのグループを作成する
+MPI_Group prime_group;
+MPI_Group_incl(world_group, 7, ranks, &prime_group);
+
+// このグループを元にしたコミュニケータを作成する
+MPI_Comm prime_comm;
+MPI_Comm_create_group(MPI_COMM_WORLD, prime_group, 0, &prime_comm);
+
+int prime_rank = -1, prime_size = -1;
+// このプロセスが新しいコミュニケータに所属しない場合、MPI_COMM_NULL になります。
+// MPI_Comm_rankまたはMPI_Comm_sizeを使う際に第一引数にMPI_COMM_NULL のコミュニケータを指定してはいけません
+if (MPI_COMM_NULL != prime_comm) {
+ MPI_Comm_rank(prime_comm, &prime_rank);
+ MPI_Comm_size(prime_comm, &prime_size);
+}
+
+printf("WORLD RANK/SIZE: %d/%d \t PRIME RANK/SIZE: %d/%d\n",
+ world_rank, world_size, prime_rank, prime_size);
+
+MPI_Group_free(&world_group);
+MPI_Group_free(&prime_group);
+MPI_Comm_free(&prime_comm);
+```
+
+この例では、`MPI_COMM_WORLD`の素数のランクのみを選択してコミュニケータを作成します。まずは `MPI_Group_incl`でグループ`prime_group`を生成します。次に、このグループを `MPI_Comm_create_group`に渡して コミュニケータ`prime_comm`を作成します。そして`ranks` に含まれていないランクの`MPI_Comm_create_group`から返されるコミュニケータが`MPI_COMM_NULL`でないことを確認してランクやグループを確認します。
+
+(以下は訳者の環境でn=8で実行した例です)
+```
+WORLD RANK/SIZE: 6/8 --- PRIME RANK/SIZE: -1/-1
+WORLD RANK/SIZE: 0/8 --- PRIME RANK/SIZE: -1/-1
+WORLD RANK/SIZE: 4/8 --- PRIME RANK/SIZE: -1/-1
+WORLD RANK/SIZE: 3/8 --- PRIME RANK/SIZE: 2/5
+WORLD RANK/SIZE: 1/8 --- PRIME RANK/SIZE: 0/5
+WORLD RANK/SIZE: 5/8 --- PRIME RANK/SIZE: 3/5
+WORLD RANK/SIZE: 2/8 --- PRIME RANK/SIZE: 1/5
+WORLD RANK/SIZE: 7/8 --- PRIME RANK/SIZE: 4/5
+```
\ No newline at end of file
diff --git a/tutorials/introduction-to-groups-and-communicators/zh_cn.md b/tutorials/introduction-to-groups-and-communicators/zh_cn.md
index c3cd193..37155ee 100644
--- a/tutorials/introduction-to-groups-and-communicators/zh_cn.md
+++ b/tutorials/introduction-to-groups-and-communicators/zh_cn.md
@@ -284,5 +284,4 @@ MPI_Comm_free(&prime_comm);
在此示例中,我们通过仅选择 `MPI_COMM_WORLD` 中的主要秩来构建通讯器。
这是通过 `MPI_Group_incl` 完成的,并将结果存储在 `prime_group` 中。
接下来,我们将该组传递给 `MPI_Comm_create_group` 以创建 `prime_comm`。
-At the end, we have to be careful to not use `prime_comm` on processes which don't have it, therefore we check to ensure that the communicator is not `MPI_COMM_NULL`, which is returned from `MPI_Comm_create_group` on the ranks not included in `ranks`.
最后,我们必须小心不要在没有 `prime_comm` 的进程上使用 `prime_comm`,因此我们要检查以确保通讯器不是 `MPI_COMM_NULL` 状态 —— 不在 `ranks` 中而从 `MPI_Comm_create_group` 返回的结果。
diff --git a/tutorials/launching-an-amazon-ec2-mpi-cluster/index.md b/tutorials/launching-an-amazon-ec2-mpi-cluster/index.md
index b529e44..db94d17 100644
--- a/tutorials/launching-an-amazon-ec2-mpi-cluster/index.md
+++ b/tutorials/launching-an-amazon-ec2-mpi-cluster/index.md
@@ -3,6 +3,7 @@ layout: post
title: Launching an Amazon EC2 MPI Cluster
author: Wes Kendall
categories: Beginner MPI
+translations: ja_jp
tags:
redirect_from: '/launching-an-amazon-ec2-mpi-cluster/'
---
diff --git a/tutorials/launching-an-amazon-ec2-mpi-cluster/ja_jp.md b/tutorials/launching-an-amazon-ec2-mpi-cluster/ja_jp.md
new file mode 100644
index 0000000..e4b621e
--- /dev/null
+++ b/tutorials/launching-an-amazon-ec2-mpi-cluster/ja_jp.md
@@ -0,0 +1,162 @@
+---
+layout: post
+title: Amazon EC2 MPIクラスタを起動する - Launching an Amazon EC2 MPI Cluster
+author: Wes Kendall
+categories: Beginner MPI
+tags:
+redirect_from: '/launching-an-amazon-ec2-mpi-cluster/'
+---
+
+[前回のレッスン]({{ site.baseurl }}/tutorials/installing-mpich2/)ではMPICH2を1台のマシンにインストールしする方法を説明しました。ただし、MPIを学習しプログラムを実行するために十分なリソースが1台のマシンで提供できるとは限りません。クラスタに簡単にアクセスできる初心者はそういないでしょう。最高のMPIチュートリアルのためには、このサイトのチュートリアルコードはもちろん、自分の並列コードを実行できる環境が必要なので、仮想MPIクラスタをセットアップする方法を説明します。
+
+## Amazon EC2で始めよう
+このレッスンではAmazonのElastic Compute Cloud (EC2)を使ったクラスタの説明をします。Amazon EC2を始めるには、[Amazon Web Services (AWS)](http://aws.amazon.com/)にアクセスし、"Sign Up "ボタンを押します。サービスを利用するには支払い情報を入力する必要があり、利用したサービスに応じて課金されます。
+
+> **Note** - AWSにサインアップする前に、必ず[EC2の価格設定](http://aws.amazon.com/ec2/pricing/)を読んでなにをしようとしているのかを理解してください。この記事を書いている時点では、AWSは一部のマシンサイズに無料時間枠を提供しており、1時間あたり2アメリカセントという低価格のマシンも提供されています。
+
+AWSにサインアップしたら、[EC2スタートガイド](http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html?r=1874)を読んでください。さまざまなインスタンスの起動、アクセス方法、終了の方法などを知っておかなければなりません。
+
+一方で、MPIクラスタを作成しアクセスするためにAmazonのEC2インフラストラクチャを完全に理解する必要はありません。EC2の基本がわかったら次のステップに進んでください。
+
+## StarCluster のインストール
+仮想クラスタを作成するために使うツールは[MITのStarCluster toolkit](http://star.mit.edu/cluster/)です。StarClusterは、EC2上にクラスタを構築してアクセス可能とする一連のプロセスを自動化したツールセットです。StarClusterはクラスタの作成・起動だけでなく、OpenMPIや並列アプリケーションのためのソフトウェアも一括でインストールしてくれます。
+
+StarClusterツールキットをローカルマシンにインストールするには(Linux/MacOSXでは)、次のように入力します:
+
+```
+$ sudo easy_install StarCluster
+```
+
+Windowsを使っている場合は[Windows installation instructions](http://star.mit.edu/cluster/docs/latest/installation.html#installing-on-windows)を参照してください。
+
+## StarClusterの設定 - Configuring StarCluster
+インストールが終わったら次のように実行してみてください。
+
+```
+$ starcluster help
+```
+
+この時点ではStarClusterは設定されていないため、以下のように出力されるでしょう(ディレクトリが私のとは異なることに注意してください)。
+
+```
+StarCluster - (http://web.mit.edu/starcluster) (v. 0.93.3)
+Software Tools for Academics and Researchers (STAR)
+Please submit bug reports to starcluster@mit.edu
+
+!!! ERROR - config file /Users/wesleykendall/.starcluster/config does not exist
+
+Options:
+--------
+[1] Show the StarCluster config template
+[2] Write config template to /Users/wesleykendall/.starcluster/config
+[q] Quit
+
+Please enter your selection:
+```
+
+2を入力しましょう。StarClusterはホームディレクトリ内の `~/.starcluster/config`にデフォルトの構成ファイルを生成します。
+
+次はAWSアカウントからAWSアクセスキー、シークレットアクセスキー、12桁のユーザーIDを取得しましょう。この情報は、[Amazon Web Services](http://aws.amazon.com/)にアクセスし、右上にある "My Account/Console "をクリックし、"My Security Credentials "をクリックすることで確認できます。
+
+
+
+"Access Credentials"セクションの中に"Access Key ID "フィールドと"Secret Access Key"フィールドがあります。ページの下部には"Account Identifiers"セクションがあり、"AWS Account ID"フィールがあります。
+
+デフォルトの設定ファイル(`~/.starcluster/config`)をテキストエディタで開き`[aws info]`の行を探し、適切なフィールドにAWSの情報を入力してください。
+
+```
+[aws info]
+AWS_ACCESS_KEY_ID = # Your Access Key ID here
+AWS_SECRET_ACCESS_KEY = # Your Secret Access Key here
+AWS_USER_ID = # Your 12-digit AWS Account ID here (no hyphens)
+```
+
+これらの情報を入力したら設定ファイルを保存してsshの公開/秘密鍵ペアを作成します。この鍵はAmazonにアップロードされ、クラスタにログインする際の認証に使用します。StarClusterで公開/秘密鍵ペアを生成しましょう。
+
+```
+$ starcluster createkey mykey -o ~/.ssh/mykey.rsa
+```
+これにより、`~/.ssh/mykey.rsa`に「mykey」キーが作成され、AWSアカウントにもキーが作成されます。Amazonの認証情報を正しく入力した場合は、次のような出力になるでしょう。
+
+```
+>>> Successfully created keypair: mykey
+>>> fingerprint: ...
+>>> contents:
+-----BEGIN RSA PRIVATE KEY-----
+...
+-----END RSA PRIVATE KEY-----
+```
+
+設定ファイルを再度開き、`[key mykey]`エントリがあることを確認してください。このエントリがない場合は、設定に次の内容を追加します。
+
+```
+[key mykey]
+KEY_LOCATION = ~/.ssh/mykey.rsa
+```
+
+そしてクラスタパラメータを設定します。デフォルトの設定では、`[cluster smallcluster]`に "smallcluster "というクラスタの設定が書かれています。デフォルトで以下のパラメータが設定されているはずでしょう。
+
+```
+[cluster smallcluster]
+KEYNAME = mykey
+CLUSTER_SIZE = 2
+CLUSTER_USER = sgeadmin
+CLUSTER_SHELL = bash
+NODE_IMAGE_ID = ami-899d49e0
+NODE_INSTANCE_TYPE = m1.small
+```
+
+このフィールドをみていきます。2つ以外のノードでクラスタを開始したい場合は、`CLUSTER_SIZE`オプションを変更してください。別のキー(例の"mykey"以外) を定義している場合は、`KEYNAME` フィールドに適切なキーを追加します。クラスタを実行すると、ネットワークファイルシステム (NFS) にマウントされたホームディレクトリを持つ `CLUSTER_USER` ユーザ名が自動的に生成されます。`NODE_IMAGE_ID` はクラスタソフトウェアのイメージIDです。最後のパラメータ `NODE_INSTANCE_TYPE` は各ノードのサイズを決定します。利用可能なインスタンスタイプとその属性のリストについては、[ここ](http://aws.amazon.com/ec2/instance-types/)を参照してください。
+
+クラスタの実行コストを決定するには、ノード数にインスタンス・タイプの時間単価を掛ければよいです。この記事を書いている時点ではm1.smallインスタンスは1時間あたり6.5アメリカセントです。費用は時間に対して課金されます。クラスタを30分間稼働させた場合、1時間分の料金が請求されます。
+
+> **Note** - t1.microインスタンスは最も安価ですが、私の場合StarClusterでクラスタを起動すると、うまく起動できません。
+
+### Starclusterのmpich2プラグインを有効にする。
+最後に、Starclusterを起動する前に、[以下の手順](http://star.mit.edu/cluster/docs/0.93.3/plugins/mpich2.html)に従って、Starcluster用の`mpich2`プラグインを有効にしてください。
+
+## クラスタの起動、アクセス、停止
+設定が終わったら次のように入力して"mpicluster"クラスタを起動します。デフォルトの構成では、デフォルトのクラスタタイプとして"smallcluster"が使用されます:
+
+```
+starcluster start mpicluster
+```
+
+このプロセスは構成によっては少し時間がかかります。コマンドの完了後StarClusterはクラスタへのアクセス、停止、および再起動に使用できるコマンドを出力します。
+
+次のコマンドでクラスタのマネージャノードにSSHでログインできます。
+
+```
+starcluster ssh manager mpicluster
+```
+
+クラスタにログインすると、カレントディレクトリは`/root`となります。コードのコンパイルは`/home/ubuntu`または`/home/sgeadmin`に移動してから行ってください。このディレクトリはNFSマウントされており、クラスタ内のすべてのノードから共有されています。
+
+次にGitHubレポジトリからこのMPIチュートリアルのコードをチェックアウトしてください。このサイトのすべてのレッスンで使用されているコードにアクセスできます。
+
+```
+git clone git://github.com/mpitutorial/mpitutorial.git
+```
+
+クラスタへのアクセスに慣れてきたらログアウトしてクラスタを停止ましょう。
+
+```
+starcluster stop mpicluster
+```
+
+クラスターは次のように入力して再度起動できます。
+
+```
+starcluster start -x mpicluster
+```
+
+クラスターを完全に終了するには、次のように入力します。
+
+```
+starcluster terminate mpicluster
+```
+
+"stop"と"terminate"の違いはなんでしょう?stopしたクラスタはまだAmazonのElastic Block Store(EBS)上にイメージが残っています。Amazon EBSの料金は保存されている量に対して課金されるため、当面クラスタを使用しない場合はクラスタのterminateをお勧めします。しっかりと[Amazon EC2 Pricing](http://aws.amazon.com/ec2/pricing/)について理解してください。
+
+## MPI クラスタの準備はできましたか? - Ready to run MPI programs on your cluster?
+ついに自分のMPIクラスタを手に入れたので、プログラムを実行しましょう。最初に[MPI hello world アプリケーション]({{ site.baseurl }}/tutorialss/mpi-hello-world/)のコンパイルと実行方法をチェックしてください。ローカルクラスタを構築して同じことを試したい場合は、[running an MPI cluster within a LAN]({{ site.baseurl }}/tutorialss/running-an-mpi cluster-within-a-lan)チュートリアルを参照してください。全てのレッスンは、[MPIチュートリアル]({{ site.baseurl }}/tutorials/)をチェックしてください。もしレッスンで何か問題があれば、以下にコメントを残してください。
\ No newline at end of file
diff --git a/tutorials/mpi-broadcast-and-collective-communication/index.md b/tutorials/mpi-broadcast-and-collective-communication/index.md
index aa0ec49..0223a56 100644
--- a/tutorials/mpi-broadcast-and-collective-communication/index.md
+++ b/tutorials/mpi-broadcast-and-collective-communication/index.md
@@ -3,7 +3,7 @@ layout: post
title: MPI Broadcast and Collective Communication
author: Wes Kendall
categories: Beginner MPI
-translations: zh_cn
+translations: zh_cn,ja_jp
tags: MPI_Barrier, MPI_Bcast, MPI_Wtime
redirect_from: '/mpi-broadcast-and-collective-communication/'
---
@@ -56,7 +56,7 @@ MPI_Bcast(
Although the root process and receiver processes do different jobs, they all call the same `MPI_Bcast` function. When the root process (in our example, it was process zero) calls `MPI_Bcast`, the `data` variable will be sent to all other processes. When all of the receiver processes call `MPI_Bcast`, the `data` variable will be filled in with the data from the root process.
## Broadcasting with MPI_Send and MPI_Recv
-At first, it might seem that `MPI_Bcast` is just a simple wrapper around `MPI_Send` and `MPI_Recv`. In fact, we can make this wrapper function right now. Our function, called `my_bcast` is located in [bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/my_bcast.c). It takes the same arguments as `MPI_Bcast` and looks like this:
+At first, it might seem that `MPI_Bcast` is just a simple wrapper around `MPI_Send` and `MPI_Recv`. In fact, we can make this wrapper function right now. Our function, called `my_bcast` is located in [my_bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/my_bcast.c). It takes the same arguments as `MPI_Bcast` and looks like this:
```cpp
void my_bcast(void* data, int count, MPI_Datatype datatype, int root,
diff --git a/tutorials/mpi-broadcast-and-collective-communication/ja_jp.md b/tutorials/mpi-broadcast-and-collective-communication/ja_jp.md
new file mode 100644
index 0000000..ab3222e
--- /dev/null
+++ b/tutorials/mpi-broadcast-and-collective-communication/ja_jp.md
@@ -0,0 +1,158 @@
+---
+layout: post
+title: MPIブロードキャストと集団通信 - MPI Broadcast and Collective Communication
+author: Wes Kendall
+categories: Beginner MPI
+tags: MPI_Barrier, MPI_Bcast, MPI_Wtime
+redirect_from: '/mpi-broadcast-and-collective-communication/'
+---
+
+ここまでの[チュートリアル]({{ site.baseurl }}/tutorials/)では、2プロセス間のポイントツーポイント通信を説明してきました。このレッスンから集団通信(Collective Communication)について学びます。集団通信はコミュニケータ内の*すべての*プロセスが関係する通信です。このレッスンでは、最初に集団通信の意味を確認し、標準的な集団通信のルーチンであるブロードキャスト(Broadcast)について説明します。
+
+> **Note** - このサイトのコードはすべて[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは[tutorials/mpi-broadcast-and-collective-communication/code]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code)にあります。
+
+## 集団通信と同期 - Collective communication and synchronization points
+集団通信を学んでいくために、最初に覚えておくべきことの1つは、プロセス間の同期が必要になるということです。つまり、すべての関連するプロセスがコード内の特定の集団通信を完了しなければ、すべてのプロセスが再び実行を開始できません。
+
+同期についてさらに詳しく説明します。MPIにはプロセスの同期専用の特別な関数があります。
+
+
+```cpp
+MPI_Barrier(MPI_Comm communicator)
+```
+
+バリアという非常にわかりやすい名前がついています。この関数は、コミュニケータ内のすべてのプロセスがこの関数を呼ぶまで全てのプロセスはこの関数でブロック(訳注:つまり、あるプロセスだけが先に進むことをバリア)します。下図の横軸がプログラム実行の時間を示し、各円はプロセスを示します。
+
+
+それぞれの図を見ていきましょう。T1では、プロセス0が`MPI_Barrier`に達しました。T2ではプロセス0はバリア関数でブロックされ、この間にプロセス1と3がバリア関数に到達しました。T3でプロセス2がようやくバリアに到達します。この結果、T4のようにすべてのプロセスが再び実行を進められます。
+
+`MPI_Barrier`の利用用途はいくつかあります。最も主な使途は並列プログラムで正確な時間測定(timed accurately)をするためです。
+
+`MPI_Barrier` はどのように実装されているのでしょうか?[sending and receiving tutorial]({{ site.baseurl }}/tutorials/mpi-send-and-receive/)のレッスンで学んだリングプログラムを思い出してください。トークンをリングのようにすべてのプロセスに渡すプログラムでした。この実装は全てのプロセスが処理を終えなければこの処理は終わらないのでバリアを実装するの1つの方式です。
+
+繰り返しになりますが、すべての集団通信は同期されている。言い換えると、そのルーチンを`MPI_Barrier`とした時にバリアが完了しないような状態ができてしまうと集団通信は正常に完了できません。`MPI_Barrier`や集団通信の関数をコミュニケータ内の全てのプロセスが呼び出すことを保証せずに呼び出そうとするとプログラムはブロック状態のまま先に進めません。これは初学者にとって非常に分かりにくいので覚えておいてください!
+
+## MPI_Bcast によるブロードキャスト - Broadcasting with MPI_Bcast
+ブロードキャスト(broadcast)は最も基本的な集団通信の1つです。ブロードキャストはある1つのプロセスがコミュニケータ内のすべてのプロセスに同じデータを送信します。ユーザ入力や構成パラメータをすべてのプロセスに送信するために使うことができます。
+
+ブロードキャストの例を次に示します。
+
+
+
+この例はプロセス0がルートプロセスでとなり、オリジナルのデータを保持しています。他のすべてのプロセスはデータのコピーを受け取ります。
+
+MPIにはブロードキャストを実現する`MPI_Bcast`関数があります。
+
+```cpp
+MPI_Bcast(
+ void* data,
+ int count,
+ MPI_Datatype datatype,
+ int root,
+ MPI_Comm communicator)
+```
+
+ルートプロセスは送信をし、他のプロセスは受信を行うのですが共通して`MPI_Bcast`関数を呼びます。ルートプロセス(この例ではプロセス0)が`MPI_Bcast`を呼ぶと`data`が他のすべてのプロセスに送信されます。すべての受信プロセスは`MPI_Bcast`でルート・プロセスからの`data`を受け取ります。
+
+## MPI_Send と MPI_Recv によるブロードキャスト - Broadcasting with MPI_Send and MPI_Recv
+`MPI_Bcast`は`MPI_Send`と`MPI_Recv`のラッパーなのでしょうか?実際、このラッパーはsendとrecvを使って簡単に実装することもできます。[my_bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/my_bcast.c)に示す`my_bcast`という関数は、`MPI_Bcast`と同じ引数をとる自作のブロードキャスト関数です。
+
+```cpp
+void my_bcast(void* data, int count, MPI_Datatype datatype, int root,
+ MPI_Comm communicator) {
+ int world_rank;
+ MPI_Comm_rank(communicator, &world_rank);
+ int world_size;
+ MPI_Comm_size(communicator, &world_size);
+
+ if (world_rank == root) {
+ // ルートプロセスはforで各プロセスにデータを送る
+ int i;
+ for (i = 0; i < world_size; i++) {
+ if (i != world_rank) {
+ MPI_Send(data, count, datatype, i, 0, communicator);
+ }
+ }
+ } else {
+ // ルートでないプロセスはルートプロセスからのデータを受け取る
+ MPI_Recv(data, count, datatype, root, 0, communicator,
+ MPI_STATUS_IGNORE);
+ }
+}
+```
+
+コメントの通りで、ルートプロセスが他のプロセスにデータを送り、他のプロセスはルートプロセスからデータを受け取る。とても簡単ですね。[レポジトリ]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/)のチュートリアルディレクトリからmy_bcastプログラムを実行してみましょう。
+
+```
+>>> cd tutorials
+>>> ./run.py my_bcast
+mpirun -n 4 ./my_bcast
+Process 0 broadcasting data 100
+Process 2 received data 100 from root process
+Process 3 received data 100 from root process
+Process 1 received data 100 from root process
+```
+
+動作はしますが、この自作関数は非常に非効率的です。各プロセスには送信/受信ネットワークのリンクが1つしかないのです。つまりプロセス0から常に1つのネットワーク リンクのみを使用することを繰り返してすべてのデータを送信します。ネットワークリンクを一度に多く使用できる賢い方法を考えましょう。ツリー(木)ベースの通信アルゴリズムです。
+
+
+
+この図を説明します。最初のステップでプロセス0はデータをプロセス1に送信します。次のステップでプロセス0もデータをプロセス2に送信します。さらにプロセス1はプロセス3にデータを送信します。他のプロセスがルートプロセスを助けて2つのネットワーク接続がブロードキャストに使用されています。このようにすべてのプロセスがデータを受信するまで各ステップごとにネットワークの使用率は2倍になります。
+
+この実装コードを書くことはレッスンの目的から少し外れます。詳細が気になる場合は[Parallel Programming with MPI](http://www.amazon.com/gp/product/1558603395/ref=as_li_qf_sp_asin_tl?ie=UTF8&tag=softengiintet-20&linkCode=as2&camp=217145&creative=399377&creativeASIN=1558603395)を参照してください。コードの問題の完全な例が掲載されている優れた本です。
+
+## MPI_Bcast と MPI_Send および MPI_Recv との比較 - Comparison of MPI_Bcast with MPI_Send and MPI_Recv
+`MPI_Bcast`はネットワーク利用効率の改善のために、今紹介したようなツリー型のブロードキャストアルゴリズムを利用しています。自作ブロードキャストを`MPI_Bcast`と比較してみましょう。このための`compare_bcast`を実行します。`compare_bcast`は、レッスンコードに含まれているサンプルプログラムです([compare_bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/compare_bcast.c))。コードの説明の前にまずはMPIのタイミング(timing)関数の1つである`MPI_Wtime`の説明をします。`MPI_Wtime`は引数を取らず、過去の実行の秒数を浮動小数点数で返します。うまく使用することでCの`time`関数と同じようにプログラム中で複数の`MPI_Wtime`関数を呼び出して、差分を引くことでセグメントごとの時間を取得することができる関数です。
+
+`my_bcast` と `MPI_Bcast` を比較するコードを書きます。
+
+```cpp
+for (i = 0; i < num_trials; i++) {
+ // Time my_bcast
+ // バリアをして事前時間を同期する
+ MPI_Barrier(MPI_COMM_WORLD);
+ total_my_bcast_time -= MPI_Wtime();
+ my_bcast(data, num_elements, MPI_INT, 0, MPI_COMM_WORLD);
+ // Synchronize again before obtaining final time
+ MPI_Barrier(MPI_COMM_WORLD);
+ total_my_bcast_time += MPI_Wtime();
+
+ // Time MPI_Bcast
+ MPI_Barrier(MPI_COMM_WORLD);
+ total_mpi_bcast_time -= MPI_Wtime();
+ MPI_Bcast(data, num_elements, MPI_INT, 0, MPI_COMM_WORLD);
+ MPI_Barrier(MPI_COMM_WORLD);
+ total_mpi_bcast_time += MPI_Wtime();
+}
+```
+
+`num_trials`は実行する回数を示す変数です。 2つの関数ごとに実行時間を計算します。そして平均時間をプログラムの最後で出力します。 コード全体は、[compare_bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/compare_bcast.c)を見てください。[レッスンコード]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code)で確認できます。
+
+[レポジトリ]({{ site.github.code }})の compare_bcast プログラムを実行すると出力は次のようになります。
+
+```
+>>> cd tutorials
+>>> ./run.py compare_bcast
+/home/kendall/bin/mpirun -n 16 -machinefile hosts ./compare_bcast 100000 10
+Data size = 400000, Trials = 10
+Avg my_bcast time = 0.510873
+Avg MPI_Bcast time = 0.126835
+```
+
+スクリプトは、16個のプロセッサにおいて1ブロードキャスト呼び出しあたり100,000 個の整数を送ることを10回試行します。Ethernet経由で接続された16プロセッサを使用した私の環境ではmy_bcastとMPI実装の間に大きな実行時間の差が生まれました。以下は、さまざまなプロセッサ数での結果です。
+
+| Processors | my_bcast | MPI_Bcast |
+| --- | --- | --- |
+| 2 | 0.0344 | 0.0344 |
+| 4 | 0.1025 | 0.0817 |
+| 8 | 0.2385 | 0.1084 |
+| 16 | 0.5109 | 0.1296 |
+
+2つのプロセッサでは2つの実装の時間差はありません。これは`MPI_Bcast`がツリー実装を使ったとしても、2つのプロセッサの場合はネットワーク使用率には違いがないためです。ただし16プロセッサまで増やすと違いがはっきりとわかります。
+
+試してみてください!
+
+## Conclusions / up next
+集団通信に慣れてきましたか?次は[ScatterとGather]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/)を学びましょう!
+
+その他のレッスンは[MPIチュートリアル]({{ site.baseurl }}/tutorials/)をみてください。
diff --git a/tutorials/mpi-broadcast-and-collective-communication/zh_cn.md b/tutorials/mpi-broadcast-and-collective-communication/zh_cn.md
index c507cf0..25758c9 100644
--- a/tutorials/mpi-broadcast-and-collective-communication/zh_cn.md
+++ b/tutorials/mpi-broadcast-and-collective-communication/zh_cn.md
@@ -55,7 +55,7 @@ MPI_Bcast(
尽管根节点和接收节点做不同的事情,它们都是调用同样的这个 `MPI_Bcast` 函数来实现广播。当根节点(在我们的例子是节点0)调用 `MPI_Bcast` 函数的时候,`data` 变量里的值会被发送到其他的节点上。当其他的节点调用 `MPI_Bcast` 的时候,`data` 变量会被赋值成从根节点接受到的数据。
## 使用 MPI_Send 和 MPI_Recv 来做广播
-粗略看的话,似乎 `MPI_Bcast` 仅仅是在 `MPI_Send` 和 `MPI_Recv` 基础上进行了一层包装。事实上,我们现在就可以自己来做这层封装。我们的函数叫做 `my_bcast`,在这里可以看到: [bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/my_bcast.c)。它跟 `MPI_Bcast` 接受一样的参数,看起来像这样:
+粗略看的话,似乎 `MPI_Bcast` 仅仅是在 `MPI_Send` 和 `MPI_Recv` 基础上进行了一层包装。事实上,我们现在就可以自己来做这层封装。我们的函数叫做 `my_bcast`,在这里可以看到: [my_bcast.c]({{ site.github.code }}/tutorials/mpi-broadcast-and-collective-communication/code/my_bcast.c)。它跟 `MPI_Bcast` 接受一样的参数,看起来像这样:
```cpp
void my_bcast(void* data, int count, MPI_Datatype datatype, int root,
@@ -94,7 +94,7 @@ Process 3 received data 100 from root process
Process 1 received data 100 from root process
```
-不管你信不信,其实我们的函数效率特别低!假设每个进程都只有一个「输出/输入」网络连接。我们的方法只是使用了进程0的一个输出连接来书传递数据。比较聪明的方法是使用一个基于树的沟通算法对网络进行更好的利用。比如这样:
+不管你信不信,其实我们的函数效率特别低!假设每个进程都只有一个「输出/输入」网络连接。我们的方法只是使用了进程0的一个输出连接来传递数据。比较聪明的方法是使用一个基于树的沟通算法对网络进行更好的利用。比如这样:

diff --git a/tutorials/mpi-hello-world/index.md b/tutorials/mpi-hello-world/index.md
index 775b7d8..b854bee 100644
--- a/tutorials/mpi-hello-world/index.md
+++ b/tutorials/mpi-hello-world/index.md
@@ -3,7 +3,7 @@ layout: post
title: MPI Hello World
author: Wes Kendall
categories: Beginner MPI
-translations: zh_cn
+translations: zh_cn,ja_jp
tags: MPI_Comm_rank, MPI_Comm_size, MPI_Finalize, MPI_Get_processor_name, MPI_Init
redirect_from: '/mpi-hello-world/'
---
@@ -146,7 +146,7 @@ Hello world from processor cetus3, rank 2 out of 4 processors
As expected, the MPI program was launched across all of the hosts in my host file. Each process was assigned a unique rank, which was printed off along with the process name. As one can see from my example output, the output of the processes is in an arbitrary order since there is no synchronization involved before printing.
-Notice how the script called mpirun. This is program that the MPI implementation uses to launch the job. Processes are spawned across all the hosts in the host file and the MPI program executes across each process. My script automatically supplies the *-n* flag to set the number of MPI processes to four. Try changing the run script and launching more processes! Don't accidentally crash your system though. :-)
+Notice how the script called mpirun. This is the program that the MPI implementation uses to launch the job. Processes are spawned across all the hosts in the host file and the MPI program executes across each process. My script automatically supplies the *-n* flag to set the number of MPI processes to four. Try changing the run script and launching more processes! Don't accidentally crash your system though. :-)
Now you might be asking, *"My hosts are actually dual-core machines. How can I get MPI to spawn processes across the individual cores first before individual machines?"* The solution is pretty simple. Just modify your hosts file and place a colon and the number of cores per processor after the host name. For example, I specified that each of my hosts has two cores.
@@ -158,7 +158,7 @@ cetus3:2
cetus4:2
```
-When I execute the run script again, *voila!*, the MPI job spawns two processes on only two of my hosts.
+When I execute the run script again, *voila!*, the MPI job spawns four processes on only two of my hosts.
```
>>> ./run.py mpi_hello_world
diff --git a/tutorials/mpi-hello-world/ja_jp.md b/tutorials/mpi-hello-world/ja_jp.md
new file mode 100644
index 0000000..f8643a2
--- /dev/null
+++ b/tutorials/mpi-hello-world/ja_jp.md
@@ -0,0 +1,186 @@
+---
+layout: post
+title: 初めてのMPIプログラム - MPI Hello World
+author: Wes Kendall
+categories: Beginner MPI
+tags:
+redirect_from: '/mpi-hello-world/'
+---
+
+このレッスンでは基本的なMPI Hello Worldアプリケーションの作成方法とMPIプログラムの実行方法を説明します。MPIの初期化と複数のプロセスにわたるMPIジョブの実行の基本について説明します。このレッスンは、MPICH2(1.4)のインストールで動作することを確認しています。MPICH2をインストールしていない場合は[installing MPICH2 lesson]({{ site.baseurl }}/tutorials/installing-mpich2/)を参照してください。
+
+
+> **Note** : このサイトのコードはすべて [GitHub]({{ site.github.repo }})にあります。このチュートリアルのコードは[tutorials/mpi-hello-world/code]({{ site.github.code }}/tutorials/mpi-hello-world/code)にあります。
+
+## Hello, World!: Hello world code examples
+それでは[mpi_hello_world.c]({{ site.github.code }}/tutorials/mpi-hello-world/code/mpi_hello_world.c)にあるコードを読んでいきます。
+
+
+```cpp
+#include
+#include
+
+int main(int argc, char** argv) {
+ // Initialize the MPI environment
+ // MPI環境の初期化
+ MPI_Init(NULL, NULL);
+
+ // Get the number of processes
+ // プロセスの数を得る
+ int world_size;
+ MPI_Comm_size(MPI_COMM_WORLD, &world_size);
+
+ // Get the rank of the process
+ // このコミュニケータ内の自分のランクを得る
+ int world_rank;
+ MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
+
+ // Get the name of the processor
+ // このプロセッサーの名前を得る
+ char processor_name[MPI_MAX_PROCESSOR_NAME];
+ int name_len;
+ MPI_Get_processor_name(processor_name, &name_len);
+
+ // Print off a hello world message
+ // Hello, World!を表示する。
+ printf("Hello world from processor %s, rank %d out of %d processors\n",
+ processor_name, world_rank, world_size);
+
+ // Finalize the MPI environment.
+ // MPI環境をクローズする
+ MPI_Finalize();
+}
+```
+
+MPIプログラムではMPIヘッダのインクルードが必要です(`#include `)。次にMPI環境を初期化する必要があります。
+
+
+
+```cpp
+MPI_Init(
+ int* argc,
+ char*** argv)
+```
+
+`MPI_Init`: MPIのグローバル変数と内部変数が初期化・設定されます。このプログラムでは、全てのプロセスのそれぞれにランクを割り当て、それら全てを含むコミュニケータを作成します。`MPI_Init`は特に設定する引数がありません。追加のパラメータは将来の実装で必要になった場合に備えて予約されています。
+
+`MPI_Init`の後には2つの関数を呼び出します。これらはほとんど全てのMPIプログラムで呼び出されるコードです。
+
+```cpp
+MPI_Comm_size(
+ MPI_Comm communicator,
+ int* size)
+```
+
+`MPI_Comm_size`はコミュニケータのサイズを返します。サンプルで引数に与えている`MPI_COMM_WORLD`(MPIにより初期化される変数)はジョブ内のすべてのプロセスを含むのでこの呼び出しはジョブに要求したプロセスの数を返します。
+
+```cpp
+MPI_Comm_rank(
+ MPI_Comm communicator,
+ int* rank)
+```
+
+`MPI_Comm_rank`:コミュニケータ内におけるそのプロセスのランクを返します。コミュニケータ内の各プロセスには0から順にランクが割り当てられます。ランクは主にメッセージの送受信のために使用されます。
+
+次の関数は実際のコードではあまり使われることはないでしょう。
+
+```cpp
+MPI_Get_processor_name(
+ char* name,
+ int* name_length)
+```
+
+`MPI_Get_processor_name`はプロセッサの名前を取得します。最後に呼ばれる関数も見ていきましょう。
+
+```cpp
+MPI_Finalize()
+```
+
+`MPI_Finalize`はMPI環境のクリーンアップです。この関数の後はMPI関数を使うことはできません。
+
+## アプリケーションの実行: Running the MPI hello world application
+gitからコードをcloneしてコードのフォルダを見てみましょう。その中にはMakefileがあります。
+
+```
+>>> git clone {{ site.github.repo }}
+>>> cd mpitutorial/tutorials/mpi-hello-world/code
+>>> cat makefile
+EXECS=mpi_hello_world
+MPICC?=mpicc
+
+all: ${EXECS}
+
+mpi_hello_world: mpi_hello_world.c
+ ${MPICC} -o mpi_hello_world mpi_hello_world.c
+
+clean:
+ rm ${EXECS}
+```
+
+このmakefileはMPICC環境変数が設定されているならばそれを用います。MPICH2をローカルディレクトリにインストールした場合は、MPICC環境変数を適切なmpiccバイナリパスを指すように設定してください。mpiccは必要なライブラリやインクルードを行ってくれるgccのラッパーです。
+
+```
+>>> export MPICC=/home/kendall/bin/mpicc
+>>> make
+/home/kendall/bin/mpicc -o mpi_hello_world mpi_hello_world.c
+```
+
+プログラムのコンパイルが終わり実行の準備が整いました!複数のノードのクラスターでMPIプログラムを実行する場合はホストファイルをセットアップする必要があることに注意してください。単一のマシンでMPIを実行するだけの場合は次の情報は無視してください。
+
+host_fileには、MPIジョブが実行されるすべてのコンピューターのhostnameが含まれています。実行を容易にするために、これらのホストにSSHアクセスできることを確認する必要があります。また、SSHのパスワードプロンプトを回避するために[setup an authorized keys file](http://www.eng.cam.ac.uk/help/jpmg/ssh/authorized_keys_howto.html)を設定する必要があります。たとえばhost_fileの例を示します。
+
+```
+>>> cat host_file
+cetus1
+cetus2
+cetus3
+cetus4
+```
+gitレポジトリに含まれるrun.pyで複数のホストを用いるのにはMPI_HOSTSという環境変数を設定する必要があります。これを設定してMPIジョブが起動されると、実行コマンドラインにホストファイルが自動的に含められます。hostファイルが必要ない場合は環境変数は設定不要です。また、MPIのローカルインストールで特定のmpirunバイナリを指したい場合はMPIRUN環境変数を設定する必要があります。
+
+これが完了したら、レポジトリに含まれているrun.pyを使用できます。このスクリプトは*tutorials*ディレクトリに保存されており、すべてのチュートリアルの任意のプログラムを実行できます(実行前に実行可能ファイルのビルドも試行します)。mpitutorialフォルダから次の操作を試してください。
+
+
+```
+>>> export MPIRUN=/home/kendall/bin/mpirun
+>>> export MPI_HOSTS=host_file
+>>> cd tutorials
+>>> ./run.py mpi_hello_world
+/home/kendall/bin/mpirun -n 4 -f host_file ./mpi_hello_world
+Hello world from processor cetus2, rank 1 out of 4 processors
+Hello world from processor cetus1, rank 0 out of 4 processors
+Hello world from processor cetus4, rank 3 out of 4 processors
+Hello world from processor cetus3, rank 2 out of 4 processors
+```
+
+想定通りMPIプログラムはホストファイル内のすべてのホストで動作しました。各プロセスは一意の(ユニークな)ランクを持ち、プロセス名とともに出力されました。出力例からわかるように、実行順序は同期がしていないためプロセスの出力はランダムになっています。
+
+スクリプトはmpirunを呼び出していることに注目してください。これは、MPIがジョブを起動するために使用するプログラムです。このプログラムはプロセスをホストファイル内のホストで生成し、実際のプログラムは各プロセスで実行されます。このスクリプトではMPIプロセスの数を4に設定するために`-n`フラグを自動的に提供します。実行スクリプトを変更して、より多くのプロセスを起動してみてください。ただし、誤ってシステムをクラッシュさせないようにしてくださいね。:-)
+
+さて「私のコンピュータはマルチコアなので他のノードよりも先にあるノードのコアを使いたいのだが」と思っていますか?これは簡単に制御できます。ホストファイルを変更し、ホスト名の後にコロンとプロセッサあたりのコア数を入力すれば良いです。たとえば、各ホストの2つのコアを使いたいとしましょう。
+
+```
+>>> cat host_file
+cetus1:2
+cetus2:2
+cetus3:2
+cetus4:2
+```
+
+実行スクリプトを再度実行するとMPIジョブによって2つのホストのみで4つのプロセスが生成されました!(訳注:hostsは8個のプロセスを処理できることを示しますが、要求されたのは4個のプロセスのみなので2つのホストだけが使われています)
+
+```
+>>> ./run.py mpi_hello_world
+/home/kendall/bin/mpirun -n 4 -f host_file ./mpi_hello_world
+Hello world from processor cetus1, rank 0 out of 4 processors
+Hello world from processor cetus2, rank 2 out of 4 processors
+Hello world from processor cetus2, rank 3 out of 4 processors
+Hello world from processor cetus1, rank 1 out of 4 processors
+```
+
+## 次に: Up next
+MPIプログラムの実行方法について基本的な理解ができたので、次は基本的なポイントツーポイント通信ルーチンを学習します。次のレッスンは[MPI の基本的な送信ルーチンと受信ルーチン: basic sending and receiving routines in MPI]({{ site.baseurl }}/tutorials/mpi-send-and-receive/)です。
+[MPI tutorials]({{ site.baseurl }}/tutorials/)をMPIレッスンの完全なリファレンスとして活用してください。
+
+困っていますか?混乱していますか?お気軽に下記にコメントを残してください。私や他の読者がお役に立てるかもしれません。
+
diff --git a/tutorials/mpi-hello-world/zh_cn.md b/tutorials/mpi-hello-world/zh_cn.md
index 8086380..58c15cb 100644
--- a/tutorials/mpi-hello-world/zh_cn.md
+++ b/tutorials/mpi-hello-world/zh_cn.md
@@ -109,7 +109,7 @@ clean:
rm ${EXECS}
```
-我的 makefile 会去找 MPICC 这个环境变量。如果你把 MPICH2 装在了本地文件夹里面而不是全局 PATH 下面, 手动设置一下 MPICC 这个环境变量,把它指向你的 mpicc 二进制程序。mpicc 二进制程序其实只是对 gcc 做了一层封装,使得编译和链接所有的 MPI 程序更方便。
+我的 makefile 会去找 MPICC 这个环境变量。如果你把 MPICH2 装在了本地文件夹里面而不是全局 PATH 下面, 手动设置一下 MPICC 这个环境变量,把它指向你的 mpicc 二进制程序。mpicc 二进制程序其实只是对 gcc 做了一层封装,使得编译和链接所有的 MPI 程序更方便。
```
>>> export MPICC=/home/kendall/bin/mpicc
@@ -118,7 +118,7 @@ clean:
```
当你的程序编译好之后,它就可以被执行了。不过执行之前你也许会需要一些额外配置。比如如果你想要在好几个节点的集群上面跑这个 MPI 程序的话,你需要配置一个 host 文件(不是 /etc/hosts)。如果你在笔记本或者单机上运行的话,可以跳过下面这一段。
-需要配置的 host 文件会包含你想要运行的所有节点的名称。为了运行方便,你需要确认一下所有这些节点之间能通过 SSH 通信,并且需要根据[设置认证文件这个教程]((http://www.eng.cam.ac.uk/help/jpmg/ssh/authorized_keys_howto.html)配置不需要密码的 SSH 访问。
+需要配置的 host 文件会包含你想要运行的所有节点的名称。为了运行方便,你需要确认一下所有这些节点之间能通过 SSH 通信,并且需要根据[设置认证文件这个教程](http://www.eng.cam.ac.uk/help/jpmg/ssh/authorized_keys_howto.html)配置不需要密码的 SSH 访问。
我的 host 文件看起来像这样:
```
@@ -129,7 +129,7 @@ cetus3
cetus4
```
-为了用我提供的脚本来运行这个程序,你应该设置一个叫 MPI_HOSTS 的环境变量,把它指向 host 文件所在的位置。我的脚本会自动把这个 host 文件的配置项加到 MPI 启动命令里。如果单机跑的话就不用设这个环境变量。另外如果你的 MPI 没有装到全局环境的话,你还需要指定 MPIRUN 这个环境变量指向你的 mpirun 二进制程序。
+为了用我提供的脚本来运行这个程序,你应该设置一个叫 MPI_HOSTS 的环境变量,把它指向 host 文件所在的位置。我的脚本会自动把这个 host 文件的配置项加到 MPI 启动命令里。如果单机跑的话就不用设置这个环境变量。另外如果你的 MPI 没有装到全局环境的话,你还需要指定 MPIRUN 这个环境变量指向你的 mpirun 二进制程序。
准备就绪之后你就可以使用这个项目的我提供的 python 脚本来执行程序。脚本在 *tutorials* 目录下面,这个脚本可以用来跑我们这个教程里面提到的所有程序(而且它会帮你先编译一下程序)。你可以在 mpitutorial 这个文件夹的根目录下执行以下命令:
@@ -147,9 +147,9 @@ Hello world from processor cetus3, rank 2 out of 4 processors
跟预想的一样,这个 MPI 程序运行在了我提供的所有节点上面。每个进程都被分配了一个单独的 rank,跟进程的名字一起打印出来了。你可以看到,在我们的输出的结果里,进程之间的打印顺序是任意的,因为我们的代码里并没有涉及到同步的操作。
-我们可以在打印的内容上面那条看到脚本是如何调用 mpirun 这个程序的。mpirun 是 MPI 的实现用来启动任务的一个程序。进程会在 host 文件里指定的所有机器上面生成,MPI 程序就会在所有进程上面运行。我的脚步自定地提供了一个 *-n* 参数告诉 MPI 程序我要运行 4 个进程。你可以试着修改脚步来使用更多进程运行 MPI 程序。当心别把你的操作系统玩蹦了。:-)
+我们可以在打印的内容上面那条看到脚本是如何调用 mpirun 这个程序的。mpirun 是 MPI 的实现用来启动任务的一个程序。进程会在 host 文件里指定的所有机器上面生成,MPI 程序就会在所有进程上面运行。我的脚本自定地提供了一个 *-n* 参数告诉 MPI 程序我要运行 4 个进程。你可以试着修改脚本来使用更多进程运行 MPI 程序。当心别把你的操作系统玩崩了。:-)
-你可能会问,*"我的节点都都是双核的机器,我怎么样可以让 MPI 先在每个节点上的每个核上生成进程,再去其他的机器?* 其实方案很简单。修改一下你的 host 文件,在每个节点名字的后面加一个冒号和每个处理器有的核数就行了。比如,我在 host 文件里指定我的每个节点有2个核。
+你可能会问,*“我的节点都都是双核的机器,我怎么样可以让 MPI 先在每个节点上的每个核上生成进程,再去其他的机器?”* 其实方案很简单。修改一下你的 host 文件,在每个节点名字的后面加一个冒号和每个处理器有的核数就行了。比如,我在 host 文件里指定我的每个节点有2个核。
```
>>> cat host_file
diff --git a/tutorials/mpi-introduction/index.md b/tutorials/mpi-introduction/index.md
index a7648d5..3424219 100644
--- a/tutorials/mpi-introduction/index.md
+++ b/tutorials/mpi-introduction/index.md
@@ -4,7 +4,7 @@ title: MPI Tutorial Introduction
author: Wes Kendall
categories: Beginner MPI
tags:
-translations: zh_cn
+translations: zh_cn,ja_jp
redirect_from: '/mpi-introduction/'
---
diff --git a/tutorials/mpi-introduction/ja_jp.md b/tutorials/mpi-introduction/ja_jp.md
new file mode 100644
index 0000000..e6f4e8e
--- /dev/null
+++ b/tutorials/mpi-introduction/ja_jp.md
@@ -0,0 +1,37 @@
+---
+layout: post
+title: MPI チュートリアル イントロダクション
+author: Wes Kendall
+categories: Beginner MPI
+tags:
+redirect_from: '/mpi-introduction/'
+---
+
+もはや並列計算はパソコン、スマートフォン、その他の技術と同じように人々の生活の一部となっています。これはこのWebサイトにアクセスするような方はご存じのことでしょう。並列プログラミングを学ぶというのは、学校でで学習している方・仕事のために学びたい方・趣味として学びたい方、どんな方にも今後にも活用できる非常に価値のある選択といえます。私の意見ですが、メッセージ パッシング インターフェイス(MPI)の学習は、並列プログラミングの知識を広げる正しい道です。MPI は他の多くの並列プログラミングライブラリ(Hadoopなど)よりも低レベルですが、並列プログラミングに関する知識を構築するためのとてもよい基礎となります。
+
+どうして私が、このMPIに関するリソースを作成したかを説明します。私は、大学院時代に MPIをよく使用していました。幸いにもアルゴンヌ国立研究所([Argonne National Laboratory](http://www.anl.gov))でのインターンシップ中にMPIコミュニティの重要人物と出会うことができ、博士時代には大規模なスーパーコンピューティング資源とMPIを用いたクレイジーな研究に取り組めました。しかし、このような人脈とリソースの中にあってもMPIの学習は依然として難しいと未だに思っています。
+
+MPI学習が難しいと感じたのには3つの理由があります。まず、MPI学習のオンラインリソースは時代遅れか不十分な内容でした。次に、自分でクラスタを簡単に利用・構築する方法が記載されたリソースを見つけるのは困難でした。最後に、大学院時代の最も安価なMPIの本は60ドルもしました。これは大学院生にとっては高額です。現代おける並列プログラミングの重要性を考えると、並列アプリケーションのための基本的なインターフェイスの1つに関する情報に人々がアクセスがとても重要だと考えています。
+
+私はMPIの専門家ではありません。ですが、大学院時代に学んだMPIに関するすべての情報を、*皆さん自身の*クラスタで実行できるサンプルコードを含む簡単なチュートリアル形式で広めることは有益だと考えています。このWebサイトの情報が皆さんのキャリア、研究、または人生にとって貴重なツールとなることを願っています。並列プログラミングは現在だけでなく*未来でもある*からです。
+
+## MPIの歴史(概略): A brief history of MPI
+1990年代以前、現在のMPIのようなスタイルで並列計算プログラムを書くことはできませんでした。異なるコンピュータアーキテクチャに対するプログラミングと言うのは困難で退屈を極めました。いくつかのライブラリが生まれましたがそれらが標準となることはありませんでした。
+
+その時代の並列アプリケーションはほとんどが科学や研究領域のためのものでした。この中で、最も一般的に採用されたライブラリのモデルがメッセージ・パッシング・モデルです。このモデルを利用するアプリケーションは、あるタスクを実行するためにプロセス間でメッセージを受け渡しを行います。このモデルは並列アプリケーションで非常にうまく機能します。マネージャー・プロセスはワーカー・プロセスに操作命令を含んだメッセージを渡して、ワーカー・プロセスに操作を割り当てることができます。例えばマージソートを並列処理するとします。各プロセス上はローカルのデータをソートし、そのローカルのソート済みのデータを全体でマージするために、隣接したプロセスに結果を渡します。このように多くの並列アプリケーションはメッセージパッシングモデルで表現できます。
+
+この時代に登場したライブラリはメッセージパッシングモデルであり各ライブラリ間の機能の違い少なかったため、1992年のSupercomputingカンファレンスにおいて各ライブラリの作者が集ってメッセージパッシングの実行標準インターフェースであるMessage Passing Interfaceを定義しました。これを契機にプログラマはすべての主要な並列アーキテクチャに移植可能な並列アプリケーションを書くことができるようになりました。また、現在も一般的に使われているライブラリの使われている機能やモデルもこの時から出現しました。
+
+そして1994年までに完全なインターフェースと標準が定義されこれはMPI-1と呼ばれています。とはいえ、MPIは特定の実装でなくインターフェイスの定義です。各々のアーキテクチャに対応したインタフェースを実装を作成するのは開発者に委ねられていました。しかし、幸いにもMPIの完全な実装が利用できるようになるまで、1年程度しかかかりませんでした。この最初の実装が作られた後、MPIは広く採用され今でもメッセージパッシング・アプリケーションを書くための*事実上の(デファクトの)*手法であり続けています。
+
+
+*最初のMPIプログラマ*
+
+## MPIメッセージパッシングモデルの設計: MPI's design for the message passing model
+並列プログラミングのメッセージパッシングモデルであるMPIの設計における、いくつかの古典的な概念について説明します。まずは、`コミュニケータ`という概念です。コミュニケータは互いに通信可能なプロセスのグループです。このプロセスグループでは、各プロセスに固有の`ランク`が割り当てられており、そのランクで互いを区別して明示的に通信を行います。
+
+通信の基本はプロセス間の送受信操作です。送信側のプロセスはランクとメッセージを識別するためのユニークな`タグ`を用いて別のプロセスにメッセージを送信します。受信側のプロセスは指定されたタグを持つメッセージの受信してデータを処理します。このような1つの送信者と受信者が関わる通信を`ポイント・ツー・ポイント通信`と呼びます。
+
+プロセスが他の全プロセスと通信したいことがあります。例えば、マネージャー・プロセスがワーカー・プロセスすべてにデータをブロードキャストすることを考えましょう。1つ1つの送受信を行うコードを書くのは面倒ですし、最適な方法でネットワークを利用するのも難しいです。MPIはこのような全プロセスを含む様々な種類の`集団通信(collective communication)`を扱うことができます。
+
+ポイント・ツー・ポイント通信と集団通信を組み合わせることで、非常に複雑な並列プログラムが作成できます。これらの機能は非常にパワフルな高度なメカニズムを持ちます。この説明は後のレッスンまで取っておくことにして、今は[MPIをシングルマシンにインストールする]({{ site.baseurl }}/tutorials/installing-mpich2/)か、[Amazon EC2 MPIクラスタを起動する]({{ site.baseurl }}/tutorials/launching-an-amazon-ec2-mpi-cluster/)に取り組んでください。既にMPIがインストールされているなら、それは素晴らしいに進んでください。
\ No newline at end of file
diff --git a/tutorials/mpi-reduce-and-allreduce/index.md b/tutorials/mpi-reduce-and-allreduce/index.md
index 209d263..9011084 100644
--- a/tutorials/mpi-reduce-and-allreduce/index.md
+++ b/tutorials/mpi-reduce-and-allreduce/index.md
@@ -3,7 +3,7 @@ layout: post
title: MPI Reduce and Allreduce
author: Wes Kendall
categories: Beginner MPI
-translations: zh_cn
+translations: zh_cn,ja_jp
tags: MPI_Allreduce, MPI_Reduce
redirect_from: '/mpi-reduce-and-allreduce/'
---
diff --git a/tutorials/mpi-reduce-and-allreduce/ja_jp.md b/tutorials/mpi-reduce-and-allreduce/ja_jp.md
new file mode 100644
index 0000000..3cbef83
--- /dev/null
+++ b/tutorials/mpi-reduce-and-allreduce/ja_jp.md
@@ -0,0 +1,178 @@
+---
+layout: post
+title: MPI Reduce と Allreduce - MPI Reduce and Allreduce
+author: Wes Kendall
+categories: Beginner MPI
+tags: MPI_Allreduce, MPI_Reduce
+redirect_from: '/mpi-reduce-and-allreduce/'
+---
+
+前回のレッスンでは`MPI_Scatter`と`MPI_Gather`を使用してMPIで並列に順位計算を実行するアプリケーションを説明しました。このレッスンでは、`MPI_Reduce`と`MPI_Allreduce`を説明して集団通信への理解をさらに深めます。
+
+> **Note** : このサイトのコードはすべて [GitHub]({{ site.github.repo }})にあります。このチュートリアルのコードは [tutorials/mpi-reduce-and-allreduce/code]({{ site.github.code }}/tutorials/mpi-reduce-and-allreduce/code)にあります。
+
+## Reduce - An introduction to reduce
+*reduce*は関数型プログラミングで使われる基本的な概念です。データのreduceはある関数を使用して数値のセットを小さな数値のセットにします。たとえば、`[1, 2, 3, 4, 5]`というリストがあるとしましょう。これをsum 関数でreduceすると`sum([1, 2, 3, 4, 5]) = 15`が計算されることになります。掛け算でreduceすると`multiply([1, 2, 3, 4, 5]) = 120`となります。
+
+分散されている数値の集合にreduceするのは非常に面倒です。さらに集合の順序を考慮しながらのreduceを効率的にプログラムするのも面倒です。MPIには `MPI_Reduce` 関数があり、プログラマが並列アプリケーションで行う必要のある一般的なreduceのほとんどを扱うことができます。
+
+## MPI_Reduce
+`MPI_Reduce` は`MPI_Gather` と同様、各プロセスで入力要素の配列を受け取って出力要素の配列をルートプロセスに返します。出力要素にはreduceの結果が含まれます。`MPI_Reduce`の関数定義は次のとおりです。
+
+```cpp
+MPI_Reduce(
+ void* send_data,
+ void* recv_data,
+ int count,
+ MPI_Datatype datatype,
+ MPI_Op op,
+ int root,
+ MPI_Comm communicator)
+```
+
+`send_data`引数は、各プロセスがreduceしたい`datatype`型の要素の配列のポインタです。`recv_data`はルートプロセスだけの引数でreduceの結果が格納されて`sizeof(datatype) * count`のサイズを持もちます。`op` パラメータには、データに適用したい処理を指定します。MPIには一般的なreduce演算が用意されています。自作のreduceの関数を作成することもできますがこのレッスンでは扱いません。以下にMPIでサポートされている操作を紹介します。
+
+* `MPI_MAX` - 最大値
+* `MPI_MIN` - 最小値
+* `MPI_SUM` - 合計
+* `MPI_PROD` - 乗算
+* `MPI_LAND` - 各要素の論理的なAND演算
+* `MPI_LOR` - 各要素の論理的なOR演算
+* `MPI_BAND` - 各要素のビットAND演算
+* `MPI_BOR` - 各要素のビットOR演算
+* `MPI_MAXLOC` - 最大値とそれを持つプロセスのランク
+* `MPI_MINLOC` - 最小値とそれを持つプロセスのランク
+
+`MPI_Reduce`のイメージを示します。
+
+
+
+この例では各プロセスは整数を1つ持ちます。`MPI_Reduce`はプロセス0で呼び出され`MPI_SUM`をreduce演算として使用します。合計された結果がルートプロセスに格納されます。
+
+次は各プロセスが整数を複数持った時のことを考えます。
+
+
+
+この例では各プロセスは2つの整数を持ちます。ルートのプロセスではこの2つの数値を一緒にして合計を求めるのではなく、結果を入れる配列のi番目に対して、各プロセスのi番目の数の合計を集約することに注意してください。
+つまり、すべての配列の要素を合計して1つの要素にするのではなく、各配列の要素を合計してプロセス0の結果配列のi番目の要素に格納します
+
+`MPI_Reduce` がどのように見えるか理解できたので次のトピックに進みましょう。
+
+## MPI_Reduceを使った平均の計算 - Computing average of numbers with MPI_Reduce
+一つ前のレッスンでは`MPI_Scatter`と`MPI_Gather`で数値の平均を求めましたが、`MPI_Reduce`を使うことでより簡単に実装することができます。次に[reduce_avg.c]({{ site.github.code }}/tutorials/mpi-reduce-and-allreduce/code/reduce_avg.c)を示します。
+
+```cpp
+float *rand_nums = NULL;
+rand_nums = create_rand_nums(num_elements_per_proc);
+
+// 各のプロセスのsumを求める
+float local_sum = 0;
+int i;
+for (i = 0; i < num_elements_per_proc; i++) {
+ local_sum += rand_nums[i];
+}
+
+// 各のローカル変数の平均を合計と平均を表示する
+printf("Local sum for process %d - %f, avg = %f\n",
+ world_rank, local_sum, local_sum / num_elements_per_proc);
+
+// 各プロセスで求めたsumをグローバルsumとしてreduceする
+float global_sum;
+MPI_Reduce(&local_sum, &global_sum, 1, MPI_FLOAT, MPI_SUM, 0,
+ MPI_COMM_WORLD);
+
+// 結果の表示
+if (world_rank == 0) {
+ printf("Total sum = %f, avg = %f\n", global_sum,
+ global_sum / (world_size * num_elements_per_proc));
+}
+```
+
+このコードでは各プロセスが(floatの)乱数を作成し、`local_sum`を計算します。次に、`local_sum`を`MPI_SUM`によってルートプロセスにreduceします。そして全部のプロセスの平均を`global_sum / (world_size * num_elements_per_proc)`で求めます。reduce_avgプログラムを[レポジトリ]({{ site.github.code }})の*tutorials*ディレクトリから実行しましょう。
+
+```
+>>> cd tutorials
+>>> ./run.py reduce_avg
+mpirun -n 4 ./reduce_avg 100
+Local sum for process 0 - 51.385098, avg = 0.513851
+Local sum for process 1 - 51.842468, avg = 0.518425
+Local sum for process 2 - 49.684948, avg = 0.496849
+Local sum for process 3 - 47.527420, avg = 0.475274
+Total sum = 200.439941, avg = 0.501100
+```
+
+`MPI_Reduce` について学んだので次は`MPI_Allreduce`です!
+
+## MPI_Allreduce
+ほとんどの並列アプリケーションでは、ルートプロセスだけでなく全プロセスがreduceの結果にアクセスする必要があるでしょう。`MPI_Allgather`と`MPI_Gather`の関係のように`MPI_Allreduce`は値をreduceした結果を全プロセスに配布します。関数定義は以下の通りです。
+
+```cpp
+MPI_Allreduce(
+ void* send_data,
+ void* recv_data,
+ int count,
+ MPI_Datatype datatype,
+ MPI_Op op,
+ MPI_Comm communicator)
+```
+
+`MPI_Allreduce` は `MPI_Reduce` 同じ引数に見えますがルートプロセス IDは不要です (結果が全プロセスに配布されるため)。以下に `MPI_Allreduce` の通信パターンを図示します。
+
+
+
+`MPI_Allreduce`は`MPI_Reduce`した後に`MPI_Bcast`しているのと同じです。
+
+## MPI_Allreduce による標準偏差の計算 - Computing standard deviation with MPI_Allreduce
+計算問題の多くは、問題を解くためにreduceを何度も呼び出します。ここで例に示す例は分散している数の標準偏差を求める計算です。標準偏差とは平均値からの数値のばらつきを表す尺度で、標準偏差が低ければ低いほど数値がより近くに集まっていることを意味し、標準偏差が高ければその逆です。
+
+標準偏差を求めるには、まず全ての数値の平均が必要です。次に平均からの差の2乗和を計算します。この和の平均の平方根が最終結果となります。ということは2つの和が必要ということで、2つのreduceが必要になるわけです。レッスンコードの[reduce_stddev.c]({{ site.github.code }}/tutorials/mpi-reduce-and-allreduce/code/reduce_stddev.c)でこれを示します。
+
+```cpp
+rand_nums = create_rand_nums(num_elements_per_proc);
+
+// プロセス内の合計を求める
+float local_sum = 0;
+int i;
+for (i = 0; i < num_elements_per_proc; i++) {
+ local_sum += rand_nums[i];
+}
+
+// 平均を求めるためのグローバル和を計算する
+float global_sum;
+MPI_Allreduce(&local_sum, &global_sum, 1, MPI_FLOAT, MPI_SUM,
+ MPI_COMM_WORLD);
+float mean = global_sum / (num_elements_per_proc * world_size);
+
+// 平均からの差の2乗和をローカルで合計する。
+float local_sq_diff = 0;
+for (i = 0; i < num_elements_per_proc; i++) {
+ local_sq_diff += (rand_nums[i] - mean) * (rand_nums[i] - mean);
+}
+
+// 2乗和をルートプロセスに集めて合計を取る
+float global_sq_diff;
+MPI_Reduce(&local_sq_diff, &global_sq_diff, 1, MPI_FLOAT, MPI_SUM, 0,
+ MPI_COMM_WORLD);
+
+// 標準偏差stddevは二乗差の平均の平方根。表示する。
+if (world_rank == 0) {
+ float stddev = sqrt(global_sq_diff /
+ (num_elements_per_proc * world_size));
+ printf("Mean - %f, Standard deviation = %f\n", mean, stddev);
+}
+```
+
+まず、各プロセスは要素の`local_sum`を計算します。そして`MPI_Allreduce` を使用してそれらを合計します。各プロセスは全ての平均がわかるようになったので、`local_sq_diff`を計算するための`mean` を計算します。そしてローカルで平均からの差の2乗和を計算すると、ルートプロセスは`MPI_Reduce`を使用して`global_sq_diff`を計算します。最後にルートプロセスはグローバル平方差の平均の平方根を取ることによって標準偏差を計算します。
+
+サンプルプログラムの動作結果を示します。
+
+```
+>>> ./run.py reduce_stddev
+mpirun -n 4 ./reduce_stddev 100
+Mean - 0.501100, Standard deviation = 0.301126
+```
+
+## 次は?
+`MPI_Bcast`, `MPI_Scatter`, `MPI_Gather`, `MPI_Reduce` といった一般的な集団計算の使い方に慣れたので、これらを利用した洗練された並列アプリケーションを構築してみましょう。次回のレッスンは[MPI groups and communicators]({{ site.baseurl }}/tutorials/introduction-to-groups-and-communicators/)です。
+
+全てのレッスンは、[MPIチュートリアルセクション]({{ site.baseurl }}/tutorials/)を参照してください。
diff --git a/tutorials/mpi-reduce-and-allreduce/zh_cn.md b/tutorials/mpi-reduce-and-allreduce/zh_cn.md
index bd853b4..1e2b9e3 100644
--- a/tutorials/mpi-reduce-and-allreduce/zh_cn.md
+++ b/tutorials/mpi-reduce-and-allreduce/zh_cn.md
@@ -128,7 +128,6 @@ Local sum for process 3 - 47.527420, avg = 0.475274
Total sum = 200.439941, avg = 0.501100
```
-Now it is time to move on to the sibling of `MPI_Reduce` - `MPI_Allreduce`.
现在是时候接触 `MPI_Reduce` 的同级对象 - `MPI_Allreduce` 了。
## MPI_Allreduce
@@ -151,7 +150,6 @@ MPI_Allreduce(
下图介绍了 `MPI_Allreduce` 的通信模式:

-`MPI_Allreduce` is the equivalent of doing `MPI_Reduce` followed by an `MPI_Bcast`.
`MPI_Allreduce` 等效于先执行 `MPI_Reduce`,然后执行 `MPI_Bcast`。
很简单,对吧?
diff --git a/tutorials/mpi-scatter-gather-and-allgather/index.md b/tutorials/mpi-scatter-gather-and-allgather/index.md
index 1e3c92e..787e391 100644
--- a/tutorials/mpi-scatter-gather-and-allgather/index.md
+++ b/tutorials/mpi-scatter-gather-and-allgather/index.md
@@ -4,7 +4,7 @@ title: MPI Scatter, Gather, and Allgather
author: Wes Kendall
categories: Beginner MPI
tags: MPI_Gather, MPI_Allgather, MPI_Scatter
-translations: zh_cn
+translations: zh_cn,ja_jp
redirect_from: '/mpi-scatter-gather-and-allgather/'
---
diff --git a/tutorials/mpi-scatter-gather-and-allgather/ja_jp.md b/tutorials/mpi-scatter-gather-and-allgather/ja_jp.md
new file mode 100644
index 0000000..344bd45
--- /dev/null
+++ b/tutorials/mpi-scatter-gather-and-allgather/ja_jp.md
@@ -0,0 +1,154 @@
+---
+layout: post
+title: MPI Scatter, Gather, Allgather
+author: Wes Kendall
+categories: Beginner MPI
+tags: MPI_Gather, MPI_Allgather, MPI_Scatter
+redirect_from: '/mpi-scatter-gather-and-allgather/'
+---
+
+[前のレッスン]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/)では集団通信の基本である集団コミュニケーションルーチン`MPI_Bcast`を説明しました。今回のレッスンではさらに集団通信を学んでいきましょう。非常に重要なルーチン`MPI_Scatter`と`MPI_Gather`そして`MPI_Allgather`をみていきましょう。
+
+> **Note** - 全てのコードは[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは[tutorials/mpi-scatter-gather-and-allgather/code]({{ site.github.code }}/tutorials/mpi-scatter-gather-and-allgather/code)をみてください。
+
+## MPI_Scatterとは - An introduction to MPI_Scatter
+`MPI_Scatter`は`MPI_Bcast`に似た集団通信ルーチンです。ルートプロセスはコミュニケータ内のすべてのプロセスにデータを送信します。ただし、`MPI_Bcast`はルートの持つ同じデータと全く同じデータをすべてのプロセスに送信していたのに対し、`MPI_Scatter`はルートの持つ配列のチャンクをそれぞれ異なるプロセスに送信します。
+
+
+
+`MPI_Bcast`はルートプロセス(赤)のデータを全てのプロセスにコピーしました。一方、`MPI_Scatter`は配布したい配列をプロセスランクの順に要素を分けて配布します。最初の要素 (赤) はプロセス0に配る, 2番目の要素 (緑) はプロセス1に配る、といったようにです。ルートプロセス(プロセス0)はデータの配列全体を持っており、`MPI_Scatter`は適切な要素をプロセスの受信バッファにコピーします。`MPI_Scatter`の関数定義は以下の通りです。
+
+```cpp
+MPI_Scatter(
+ void* send_data,
+ int send_count,
+ MPI_Datatype send_datatype,
+ void* recv_data,
+ int recv_count,
+ MPI_Datatype recv_datatype,
+ int root,
+ MPI_Comm communicator)
+```
+
+最初の引数`send_data`はルートプロセスにおける配布したい配列のポインタです。2番目と3番目の引数`send_count`と`send_datatype`は、各プロセスに対してどんなMPI Datatypeの要素を何個送信するかを指定します。`send_count` が1で`send_datatype`が MPI_INTならば、プロセス0は配列の最初の整数を受け取り、プロセス 1は2番目の整数を受け取ります。`send_count`が2なら、プロセス0は1,2番目の整数を担当し、プロセス1は3,4番目の整数を担当します。実際には`send_count`は配列の要素数をプロセス数で割ったものに等しいでしょう。要素数がプロセス数で割り切れない?ご心配なく。それは後で見ていきましょう。
+
+後続の引数はほぼ同様です。`recv_data`は`recv_datatype`のデータ型を持つ`recv_count`個の要素を保持できるデータのバッファです。`root`と`communicator`はルートプロセスのランクと、コミュニケータです。
+
+## MPI_Gatherとは - An introduction to MPI_Gather
+`MPI_Gather`は`MPI_Scatter`の逆の動きをする関数です。要素を1つのプロセスから多数のプロセスに分散させるのではなく、`MPI_Gather`多数のプロセスから要素を取得して1つのプロセスに集めます。このルーチンは並列ソートや並列検索などの多くの並列アルゴリズムで使われます。
+
+
+
+`MPI_Scatter` の逆と考えれば良いです。 `MPI_Gather` は各プロセスから要素を受け取ってルートプロセスに集めます。そして要素を受け取ったプロセスの順位で並べます。`MPI_Gather` の関数宣言は `MPI_Scatter` と同じです。
+
+```cpp
+MPI_Gather(
+ void* send_data,
+ int send_count,
+ MPI_Datatype send_datatype,
+ void* recv_data,
+ int recv_count,
+ MPI_Datatype recv_datatype,
+ int root,
+ MPI_Comm communicator)
+```
+
+`MPI_Gather` では、ルートプロセスだけが有効な受信バッファを持てば良いので、ルートプロセス以外は`recv_data` に `NULL` を渡して良いです。また、*recv_count* パラメータは、全プロセスからのカウントの合計ではなく、*プロセスごとに*受信した要素のカウントであることを忘れないでください。これはMPIを触ったばかりのプログラマを混乱させます。
+
+## 数値の平均 - Computing average of numbers with MPI_Scatter and MPI_Gather
+レッスンの[レポジトリ]({{ site.github.code }}/tutorials/mpi-scatter-gather-and-allgather/code)では、配列内の数値の平均を計算するサンプルプログラム([avg.c]({{ site.github.code }}/tutorials/mpi-scatter-gather-and-allgather/code/avg.c))を提供しています。MPIを使用してプロセスを分割し、プロセスごとに計算を実行し、それらの小さな結果を集約して最終的な答えを出すという簡単なプログラムです。まずは動作を確認しましょう。
+
+1. ルートプロセス(プロセス0) でランダムな内容のの配列を生成します。
+2. 配列をすべてのプロセスを分散します。各プロセスに同じ数のデータを割り当てます。
+3. 各プロセスは割り当てられた数値の平均を計算します。
+4. 各プロセスは結果をルートプロセスに収集します。ルートプロセスはこれらの数値の平均を計算して最終的な平均を取得します。
+
+```cpp
+if (world_rank == 0) {
+ rand_nums = create_rand_nums(elements_per_proc * world_size);
+}
+
+// 乱数の配列を作ります。長さは固定
+float *sub_rand_nums = malloc(sizeof(float) * elements_per_proc);
+
+// 配列を全てのプロセスにScatterする
+MPI_Scatter(rand_nums, elements_per_proc, MPI_FLOAT, sub_rand_nums,
+ elements_per_proc, MPI_FLOAT, 0, MPI_COMM_WORLD);
+
+// 各プロセスは自分に割り当てられた配列の平均を計算する
+float sub_avg = compute_avg(sub_rand_nums, elements_per_proc);
+// ルートプロセスは各プロセスの値を集める
+float *sub_avgs = NULL;
+if (world_rank == 0) {
+ sub_avgs = malloc(sizeof(float) * world_size);
+}
+MPI_Gather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT, 0,
+ MPI_COMM_WORLD);
+
+// ルートプロセスは集めた平均を計算する
+if (world_rank == 0) {
+ float avg = compute_avg(sub_avgs, world_size);
+}
+```
+
+最初にルートプロセスは乱数の配列を作成します。 `MPI_Scatter`によって各プロセスには`elements_per_proc`のデータが配布されます。各プロセスは自分に割り当てられた配列の平均を計算し、ルートプロセスはそれぞれの平均を収集します。ルートプロセスでの全体の平均計算処理は、非常に小さい配列に基づいて計算すれば良いです。
+
+[レポジトリ]({{ site.github.code }})のチュートリアルディレクトリから avg プログラムを実行すると、出力は次のようになります。数字はランダムなので、この出力結果と異なるでしょう。
+
+```
+>>> cd tutorials
+>>> ./run.py avg
+/home/kendall/bin/mpirun -n 4 ./avg 100
+Avg of all elements is 0.478699
+Avg computed across original data is 0.478699
+```
+
+## MPI_Allgatherと平均プログラムの修正 - MPI_Allgather and modification of average program
+さて、多くのプロセスが1つのプロセスに対してある送受信を行う、つまり多対1または1対多の通信パターンを実行する2つのMPIルーチンをみてきました。ところで、複数のプロセルから多くのプロセスに要素を送信できることは便利です。そう、多対多の集団通信パターンです。`MPI_Allgather`というルーチンを説明します。
+
+`MPI_Allgather`は全プロセスに分散している要素を全プロセスに配布するルーチンです。つまり、`MPI_Allgather`は`MPI_Gather`を行った後に`MPI_Bcast`しているような動作をします。下図は`MPI_Allgather`を呼び出したデータの動きです。
+
+
+
+`MPI_Gather`と同じように、各プロセスに対して各プロセスが持っていた要素をランク順に集める。それだけです。`MPI_Allgather`の引数は`MPI_Gather`とほぼ同じですが、`MPI_Allgather`にはルートプロセスの引数は存在しません。
+
+```cpp
+MPI_Allgather(
+ void* send_data,
+ int send_count,
+ MPI_Datatype send_datatype,
+ void* recv_data,
+ int recv_count,
+ MPI_Datatype recv_datatype,
+ MPI_Comm communicator)
+```
+
+`MPI_Allgather`を使うように平均計算コードを修正しました。このレッスンのコードからall_avg.c]({{ site.github.code }}/tutorials/mpi-scatter-gather-and-allgather/code/all_avg.c)のソースを見ることができます。コードの主な違いは次のとおりです。
+
+```cpp
+// 全てのプロセスに対して各プロセスで計算した平均を集める
+float *sub_avgs = (float *)malloc(sizeof(float) * world_size);
+MPI_Allgather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT,
+ MPI_COMM_WORLD);
+
+// 各プロセスは全ての平均を求める
+float avg = compute_avg(sub_avgs, world_size);
+```
+
+各プロセスの平均を`MPI_Allgather`を使って全プロセスに集めます。そして、すべてのプロセスでその平均を計算して出力します。
+
+```
+>>> ./run.py all_avg
+/home/kendall/bin/mpirun -n 4 ./all_avg 100
+Avg of all elements from proc 1 is 0.479736
+Avg of all elements from proc 3 is 0.479736
+Avg of all elements from proc 0 is 0.479736
+Avg of all elements from proc 2 is 0.479736
+```
+
+このようにall_avg.c では`MPI_Allgather`で全てのプロセスに各プロセスの平均を集めて表示します。
+
+## Up next
+次のレッスンでは `MPI_Gather`と`MPI_Scatter`を利用して[並列なランク計算]({{ site.baseurl }}/tutorials/performing-parallel-rank-with-mpi/)を説明します。
+
+その他のレッスンは[MPI tutorials]({{ site.baseurl }}/tutorials/) にあります。
\ No newline at end of file
diff --git a/tutorials/mpi-send-and-receive/index.md b/tutorials/mpi-send-and-receive/index.md
index dcdce4b..c76f236 100644
--- a/tutorials/mpi-send-and-receive/index.md
+++ b/tutorials/mpi-send-and-receive/index.md
@@ -3,7 +3,7 @@ layout: post
title: MPI Send and Receive
author: Wes Kendall
categories: Beginner MPI
-translations: zh_cn
+translations: zh_cn,ja_jp
tags: MPI_Recv, MPI_Send
redirect_from: '/mpi-send-and-receive/'
---
diff --git a/tutorials/mpi-send-and-receive/ja_jp.md b/tutorials/mpi-send-and-receive/ja_jp.md
new file mode 100644
index 0000000..fcaf21d
--- /dev/null
+++ b/tutorials/mpi-send-and-receive/ja_jp.md
@@ -0,0 +1,200 @@
+---
+layout: post
+title: MPIのsendとreceive - MPI Send and Receive
+author: Wes Kendall
+categories: Beginner MPI
+tags: MPI_Recv, MPI_Send
+redirect_from: '/mpi-send-and-receive/'
+---
+
+送信と受信(send,recv)は、MPIもっとも基本的な概念です。MPIのほぼすべての機能はsend,recvをによって実装できます。このレッスンではブロッキング送受信について説明し、MPIのデータ送信の基本的な概念を説明します。
+
+> **Note** - このサイトのコードはすべて[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは[tutorials/mpi-send-and-receive/code]({{ site.github.code }}/tutorials/mpi-send-and-receive/code)にあります。
+
+## MPI による送受信の概要: Overview of sending and receiving with MPI
+MPIの基本的な送受信を見ていきましょう。まず、プロセス*A*は、プロセス*B*にメッセージを送信したいとします。プロセス*A*はプロセス*B*に送信したいデータをすべて1つにまとめて(パックして)バッファに格納します。このバッファは、データを1つのメッセージにまとめているのでエンベロープ(*envelopes*)と呼ばれることがあります(郵便の手紙が封筒にパックされるのと同じです)。データがバッファにパックされた後は通信デバイス(多くはネットワークでしょう)がメッセージを適切にルーティングします。メッセージにおける宛先はプロセスのランクによって定義されます。
+
+メッセージは*B*にむけてルーティングされます。次にプロセス*B*は*A*からデータを受信する意思があることを明確に通知(acknowledge)する必要があります。通知が完了するとデータは送信されたことになり、プロセス*A*に対してデータが送信されたことが通知され、Aのブロッキングは完了し、次の処理に移れます。
+
+次はAがBにいくつかのタイプ種類のメッセージを送信することを考えます。Bがこれらのメッセージを区別するために特別な方法を取らずとも、MPIはメッセージにID (タグ - tagsと呼ばれる)をつけた送信と受信ができます。プロセスBは特定のタグのメッセージのみを要求でき、その他の異なるタグのメッセージはBがそれを受け取る要求をするまでネットワークレイヤによってバッファリングされています。
+
+MPI send関数とrecv関数の定義を見てみましょう。
+
+```cpp
+MPI_Send(
+ void* data,
+ int count,
+ MPI_Datatype datatype,
+ int destination,
+ int tag,
+ MPI_Comm communicator)
+```
+
+```cpp
+MPI_Recv(
+ void* data,
+ int count,
+ MPI_Datatype datatype,
+ int source,
+ int tag,
+ MPI_Comm communicator,
+ MPI_Status* status)
+```
+
+複雑で長い引数に見えるかもしれませんが、多くのMPI関数では同様の構文が使用されるためご安心ください。最初の引数はデータバッファのアドレスです。2番目と3番目の引数は、バッファー内にある要素の数とタイプです。`MPI_Send`は正確な数の要素を送信し、`MPI_Recv`は"最低でも"count個の要素を受信します(これについては次のレッスンで詳しく説明します)。4番目と5番目の引数は、sendあるいはrecvするプロセスのランクとタグを指定します。6番目の引数はコミュニケータを指定します。recvのみに含まれる最後の引数`status`は、受信したメッセージに関する情報のポインタです。
+
+## 基本的な MPI データ型 - Elementary MPI datatypes
+`MPI_Send`と`MPI_Recv`関数は、メッセージのデータ構造をC言語のデータ型ではなくて、より高いレベルのデータ型で指定できます。たとえば、プロセスが1つの整数の送信する場合、カウント1と`MPI_INT`データ型を使用します。基本的なMPIデータ型と、それに相当するC言語のデータ型を以下に示します。
+
+| MPIデータ型 | C言語のデータ型 |
+| ---------------------- | ---------------------- |
+| MPI_SHORT | short int |
+| MPI_INT | int |
+| MPI_LONG | long int |
+| MPI_LONG_LONG | long long int |
+| MPI_UNSIGNED_CHAR | unsigned char |
+| MPI_UNSIGNED_SHORT | unsigned short int |
+| MPI_UNSIGNED | unsigned int |
+| MPI_UNSIGNED_LONG | unsigned long int |
+| MPI_UNSIGNED_LONG_LONG | unsigned long long int |
+| MPI_FLOAT | float |
+| MPI_DOUBLE | double |
+| MPI_LONG_DOUBLE | long double |
+| MPI_BYTE | char |
+
+これらのデータ型は初心者向けの次のMPIチュートリアルでのみ使用します。基礎を学習したら複雑なメッセージを扱うための独自のMPIデータ型を作成する方法も学習します。
+
+## MPI send / recv program
+それではコードを見ていきます。冒頭にあるように、このサイトのコードはすべて[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは[tutorials/mpi-send-and-receive/code]({{ site.github.code }}/tutorials/mpi-send-and-receive/code)にあります。
+
+最初に見るのは[send_recv.c]({{ site.github.code }}/tutorials/mpi-send-and-receive/code/send_recv.c). です。プログラムのメインとなる一部は以下の通りです。
+
+```cpp
+// Find out rank, size
+int world_rank;
+MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
+int world_size;
+MPI_Comm_size(MPI_COMM_WORLD, &world_size);
+
+int number;
+if (world_rank == 0) {
+ number = -1;
+ MPI_Send(&number, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
+} else if (world_rank == 1) {
+ MPI_Recv(&number, 1, MPI_INT, 0, 0, MPI_COMM_WORLD,
+ MPI_STATUS_IGNORE);
+ printf("Process 1 received number %d from process 0\n",
+ number);
+}
+```
+
+`MPI_Comm_rank`と`MPI_Comm_size`はワールドサイズとプロセスのランクを得るための関数です。プロセス0は整数データを-1に初期化し、この値をプロセス1に送信します。ステートメントでわかるように、プロセス1は数値を受信するために`else if`で分岐して、受信した値も出力します。送受信したいのは1つのINTだけなので、各プロセスは1つの`MPI_INT`の送信と受信を行います。また、メッセージを識別するためにタグ番号0を指定しました。送信されるメッセージの種類は1種類なのでプロセスはタグ番号に定義済みの定数`MPI_ANY_TAG`を使用してもよいです。
+
+サンプルコードの全文は[GitHub]({{ site.github.repo }}) で確認できますし、`run.py` を使って実行することもできます。
+
+```
+>>> git clone {{ site.github.repo }}
+>>> cd mpitutorial/tutorials
+>>> ./run.py send_recv
+mpirun -n 2 ./send_recv
+Process 1 received number -1 from process 0
+```
+
+プロセス1はプロセス0から-1を受け取りましたことがわかります。
+
+## MPI ping - MPI ping pong program
+次の例はpingプログラムです。この例では、プロセスは`MPI_Send`と`MPI_Recv`を利用して停止するまでメッセージを送受信します。[ping_pong.c]({{ site.github.code }}/tutorials/mpi-send-and-receive/code/ping_pong.c)を参照してください。コードのメイン部分は次の通りです。
+
+```cpp
+int ping_pong_count = 0;
+int partner_rank = (world_rank + 1) % 2;
+while (ping_pong_count < PING_PONG_LIMIT) {
+ if (world_rank == ping_pong_count % 2) {
+ // Increment the ping pong count before you send it
+ ping_pong_count++;
+ MPI_Send(&ping_pong_count, 1, MPI_INT, partner_rank, 0,
+ MPI_COMM_WORLD);
+ printf("%d sent and incremented ping_pong_count "
+ "%d to %d\n", world_rank, ping_pong_count,
+ partner_rank);
+ } else {
+ MPI_Recv(&ping_pong_count, 1, MPI_INT, partner_rank, 0,
+ MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+ printf("%d received ping_pong_count %d from %d\n",
+ world_rank, ping_pong_count, partner_rank);
+ }
+}
+```
+
+このコードは2つのプロセスのみで実行されることを想定します。プロセスは最初に簡単な演算で相手のランクを決定します。`ping_pong_count`は0で初期化し、プロセスの各送信ステップで+1します。そして、送信側と受信側を交互に担当します(訳註:一般的なpingと違い、互いに自発的にフレームを送ることに注意)。最後に、limitの回数に達すると(私のコードでは10)プロセスは動作を停止します。出力は次のようになります。
+
+```
+>>> ./run.py ping_pong
+0 sent and incremented ping_pong_count 1 to 1
+0 received ping_pong_count 2 from 1
+0 sent and incremented ping_pong_count 3 to 1
+0 received ping_pong_count 4 from 1
+0 sent and incremented ping_pong_count 5 to 1
+0 received ping_pong_count 6 from 1
+0 sent and incremented ping_pong_count 7 to 1
+0 received ping_pong_count 8 from 1
+0 sent and incremented ping_pong_count 9 to 1
+0 received ping_pong_count 10 from 1
+1 received ping_pong_count 1 from 0
+1 sent and incremented ping_pong_count 2 to 0
+1 received ping_pong_count 3 from 0
+1 sent and incremented ping_pong_count 4 to 0
+1 received ping_pong_count 5 from 0
+1 sent and incremented ping_pong_count 6 to 0
+1 received ping_pong_count 7 from 0
+1 sent and incremented ping_pong_count 8 to 0
+1 received ping_pong_count 9 from 0
+1 sent and incremented ping_pong_count 10 to 0
+```
+
+出力はプロセススケジューリングのため異なる可能性があります。ただし、出力が例と違ってもプロセス0とプロセス1は、交互に`ping_pong_count`ことが読み取れるでしょう。
+
+## Ring Program
+`MPI_Send`と`MPI_Recv`を使って2つ以上のプロセスで通信することを考えましょう。この例では、値をすべてのプロセス上をリング状に流れていきます。[ring.c]({{ site.github.code }}/tutorials/mpi-send-and-receive/code/ring.c)を見てください。コードのメイン部分は次のようになります。
+
+```cpp
+int token;
+if (world_rank != 0) {
+ MPI_Recv(&token, 1, MPI_INT, world_rank - 1, 0,
+ MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+ printf("Process %d received token %d from process %d\n",
+ world_rank, token, world_rank - 1);
+} else {
+ // ランク0はトークンを-1で初期化する
+ token = -1;
+}
+MPI_Send(&token, 1, MPI_INT, (world_rank + 1) % world_size,
+ 0, MPI_COMM_WORLD);
+
+// ここでプロセス0はリンク上の最後の受信処理を行います
+if (world_rank == 0) {
+ MPI_Recv(&token, 1, MPI_INT, world_size - 1, 0,
+ MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+ printf("Process %d received token %d from process %d\n",
+ world_rank, token, world_size - 1);
+}
+```
+
+リングプログラムはプロセス0で値を初期化し、その値を次のプロセスに渡します。プロセス0が最後のプロセスから値を受信するとプログラムは終了します。デッドロックが発生しないように特別なロジックになっています。プロセス0は(最後のプロセスから)値をブロッキング受信する前に、最初の送信を完了していることが保証されます。他のすべてのプロセスはリングに沿って値を渡します。`MPI_Recv`(隣接するランクの低いプロセスから受信)で値を受け取り、次に`MPI_Send`(隣接するランクの高いプロセスに値を送信) を呼び出します。メッセージが送信されるまでブロックします。このため、printfは値が渡される順序で実行されます。5つのプロセスを使用する場合、出力は次のようになりました。
+
+```
+>>> ./run.py ring
+Process 1 received token -1 from process 0
+Process 2 received token -1 from process 1
+Process 3 received token -1 from process 2
+Process 4 received token -1 from process 3
+Process 0 received token -1 from process 4
+```
+
+プロセス0は最初にプロセス1に-1を送信します。この値(トークン)はプロセス0に戻るまでリング状に渡されています。
+
+## Up next
+
+`MPI_Send`と`MPI_Recv`の基本を理解したのでこれらの関数についてもう少し詳しく見ていきます。次のレッスンは、[how to probe and dynamically receive messages]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/)です。[MPI tutorials]({{ site.baseurl }}/tutorials/)をMPIレッスンの完全なリファレンスとして活用してください。
+
+困っていますか?混乱していますか?お気軽に下記にコメントを残してください。私や他の読者がお役に立てるかもしれません。
diff --git a/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c b/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c
index 2dd1634..8ecdb3a 100644
--- a/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c
+++ b/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c
@@ -104,8 +104,8 @@ int *get_ranks(void *gathered_numbers, int gathered_number_count, MPI_Datatype d
return ranks;
}
-// Gets the rank of the recv_data, which is of type datatype. The rank is returned
-// in send_data and is of type datatype.
+// Gets the rank of the send_data, which is of type datatype. The rank is returned
+// in recv_data and is of type datatype.
int TMPI_Rank(void *send_data, void *recv_data, MPI_Datatype datatype, MPI_Comm comm) {
// Check base cases first - Only support MPI_INT and MPI_FLOAT for this function.
if (datatype != MPI_INT && datatype != MPI_FLOAT) {
diff --git a/tutorials/performing-parallel-rank-with-mpi/index.md b/tutorials/performing-parallel-rank-with-mpi/index.md
index 60552d0..607a71e 100644
--- a/tutorials/performing-parallel-rank-with-mpi/index.md
+++ b/tutorials/performing-parallel-rank-with-mpi/index.md
@@ -4,12 +4,13 @@ title: Performing Parallel Rank with MPI
author: Wes Kendall
categories: Beginner MPI
tags: MPI_Type_size
-translations: zh_cn
+translations: zh_cn,ja_jp
redirect_from: '/performing-parallel-rank-with-mpi/'
---
In the [previous lesson]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/), we went over `MPI_Scatter`, `MPI_Gather`, and `MPI_Allgather`. We are going to expand on basic collectives in this lesson by coding a useful function for your MPI toolkit - parallel rank.
+
> **Note** - All of the code for this site is on [GitHub]({{ site.github.repo }}). This tutorial's code is under [tutorials/performing-parallel-rank-with-mpi/code]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code).
## Parallel rank - problem overview
@@ -137,7 +138,7 @@ int *get_ranks(void *gathered_numbers, int gathered_number_count,
}
```
-The `get_ranks` function first creates an array of `CommRankNumber` structs and attaches the communicator rank of the process that owns the number. If the datatype is `MPI_FLOAT`, `qsort` is called with a special sorting function for our array of structs (see [tmpi_rank.c]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code) for the code). Likewise, we use a different sorting function if the datatype is `MPI_INT`.
+The `get_ranks` function first creates an array of `CommRankNumber` structs and attaches the communicator rank of the process that owns the number. If the datatype is `MPI_FLOAT`, `qsort` is called with a special sorting function for our array of structs (see [tmpi_rank.c]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c) for the code). Likewise, we use a different sorting function if the datatype is `MPI_INT`.
After the numbers are sorted, we must create an array of ranks in the proper order so that they can be scattered back to the requesting processes. This is accomplished by making the `ranks` array and filling in the proper rank values for each of the sorted `CommRankNumber` structs.
@@ -145,8 +146,8 @@ After the numbers are sorted, we must create an array of ranks in the proper ord
Now that we have our two primary functions, we can put them all together into our `TMPI_Rank` function. This function gathers the numbers to the root process, sorts the numbers to determine their ranks, and then scatters the ranks back to the requesting processes. The code is shown below:
```cpp
-// Gets the rank of the recv_data, which is of type datatype. The rank
-// is returned in send_data and is of type datatype.
+// Gets the rank of the send_data, which is of type datatype. The rank
+// is returned in recv_data and is of type datatype.
int TMPI_Rank(void *send_data, void *recv_data, MPI_Datatype datatype,
MPI_Comm comm) {
// Check base cases first - Only support MPI_INT and MPI_FLOAT for
diff --git a/tutorials/performing-parallel-rank-with-mpi/ja_jp.md b/tutorials/performing-parallel-rank-with-mpi/ja_jp.md
new file mode 100644
index 0000000..5ed944d
--- /dev/null
+++ b/tutorials/performing-parallel-rank-with-mpi/ja_jp.md
@@ -0,0 +1,199 @@
+---
+layout: post
+title: 並列ランク問題 - Performing Parallel Rank with MPI
+author: Wes Kendall
+categories: Beginner MPI
+tags: MPI_Type_size
+translations: zh_cn
+redirect_from: '/performing-parallel-rank-with-mpi/'
+---
+
+[前のレッスン]({{ site.baseurl }}/tutorials/mpi-scatter-gather-and-allgather/)では
+ `MPI_Scatter`, `MPI_Gather`, `MPI_Allgather`を紹介しました。このレッスンでは、MPIの便利なルーチンである並列ランク(parallel rank)を実装して集団通信への理解を深めていきましょう。
+
+> **Note** - 全てのコードは[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは [tutorials/performing-parallel-rank-with-mpi/code]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code)にあります。
+
+## 問題概要 - Parallel rank - problem overview
+すべてのプロセスがローカル メモリにただ1つの数値を持っています。各プロセスは自分の持っている数値が全てのプロセスの中で何番目に小さい値を持っているのか知りたいです。このシナリオは、ユーザーがMPIクラスター内のプロセッサのベンチマークを行っており自分のプロセッサが他のプロセッサと比較してどのくらい高速であるかを知りたいケースなどに利用されます。他にもタスクのスケジュール設定などに使用できるでしょう。数値がプロセス全体に分散していると全ての数値の中での順序を見つけるのは難しいように思えます。この問題を並列ランク問題と呼び、このレッスンで解決しましょう。
+
+具体例を図で示します。
+
+
+
+4つのプロセスがあり、0から3のラベルでそれぞれを区別します。順番に5、2、7、4の4つの数字を持っているとしましょう。並列ランクアルゴリズムを実行すると全体での順番がわかるのでそれぞれは2,0,3,1の4つの数字を持つことになります。(訳注:0-indexedです)
+
+## 並列ランクAPI定義
+これを実現するためにがなにが必要かを考えましょう。すべての数値を集めること、その数値の順番を返す必要があります。さらに使用されているコミュニケータやランク付けされる数値のデータ型なども必要になります。ランク関数のプロトタイプを次のようにしましょう。
+
+```cpp
+TMPI_Rank(
+ void *send_data,
+ void *recv_data,
+ MPI_Datatype datatype,
+ MPI_Comm comm)
+```
+
+`TMPI_Rank`は、データ型の数値を1つ含む`send_data`バッファを受け取ります。`recv_data`は、`send_data`の各プロセスの順位を受け取る変数です。`comm`変数はプロセスのコミュニケータです。
+
+> **Note** -
+> MPI標準では、ユーザー関数と MPI関数が混同しないように、MPI関数には`MPI_`という名前づけがされています。したがって、このレッスンではさらに`T`を追加しています。
+
+## 並列ランク問題の解き方 - Solving the parallel rank problem
+API定義ができたので、どのように解くかを考えましょう。並列ランク問題を解決するためには全てのプロセスから集めた数値のソートが必要です。このソートは各数字の順番を知るために必要で、いくつかのアプローチで実現できます。最も簡単な方法は各プロセスの数字を1つのプロセスに集め、そのプロセスでソートすれば良いでしょう。サンプル コード ([tmpi_rank.c]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c)) では`gather_numbers_to_root`関数はすべての数字をルート プロセスに集める役割を担います。
+
+```cpp
+// ルートプロセスに数値を集めます。
+// ルートプロセスは結果の(ランクの)配列を返します。他のプロセスにはNULLを返します。
+void *gather_numbers_to_root(void *number, MPI_Datatype datatype,
+ MPI_Comm comm) {
+ int comm_rank, comm_size;
+ MPI_Comm_rank(comm, &comm_rank);
+ MPI_Comm_size(comm, &comm_size);
+
+ // ルートプロセスでは必要なバッファを用意します。データ型のサイズを配慮します
+ int datatype_size;
+ MPI_Type_size(datatype, &datatype_size);
+ void *gathered_numbers;
+ if (comm_rank == 0) {
+ gathered_numbers = malloc(datatype_size * comm_size);
+ }
+
+ // 全ての数値をルートプロセスに集めます
+ MPI_Gather(number, 1, datatype, gathered_numbers, 1,
+ datatype, 0, comm);
+
+ return gathered_numbers;
+}
+```
+
+`gather_numbers_to_root`関数はルートに送りたい数値(`send_data`変数)と数値の`datatype`および`comm`コミュニケータを引数で受け取ります。ルート・プロセスは`comm_size`の数値を受け取ればいいとわかるので`datatype_size * comm_size`の長さの配列をメモリ確保します。`datatype_size`変数は、このチュートリアルで初めて使う`MPI_Type_size`を使用して収集されます。私たちの今回のプログラムは`MPI_INT`と`MPI_FLOAT`のみを使用しますが、この関数を使うと様々なサイズのデータ型をサポートするように拡張することができます。これで数値が集まったので`MPI_Gather`でルートプロセスに数を集めます。次はルートプロセスで数をソートし、ランクを決定します。
+
+## ソートとその所有権の維持 - Sorting numbers and maintaining ownership
+ソートの処理自身は難しくありません。C標準ライブラリには`qsort` などの一般的なソートアルゴリズムが用意されています。ただし、並列ランク問題ソートでは数字を送信したプロセスのランクをルートプロセスのソートの間で維持する必要あることに注意します。ルートプロセス対して数字だけでは数字の順位をどのプロセスに返せばいいかわからないのです。
+
+数字とそれに対応する送信元のプロセスのランク(つまり所有権)を保持する構造体を定義しましょう。
+
+```cpp
+// 値とコミュニケータランクを保持する
+// この構造体はソートをされてもランクの情報を失わない
+typedef struct {
+ int comm_rank;
+ union {
+ float f;
+ int i;
+ } number;
+} CommRankNumber;
+```
+
+構造体`CommRankNumber`はソートする数値を保持し、対応するプロセスのコミュニケータランクを保持します。ここで数値はfloatまたはintの可能性があるので、unionで両方を保持できるようにしていることに注意してください。次にこの構造体をソートする`get_ranks`関数を考えていきましょう。
+
+```cpp
+// この関数はルートプロセスに値を集めて、その順位を元のプロセスに返します
+// この関数はルートでのみ実行されます。
+int *get_ranks(void *gathered_numbers, int gathered_number_count,
+ MPI_Datatype datatype) {
+ int datatype_size;
+ MPI_Type_size(datatype, &datatype_size);
+
+ // 集めた値をCommRankNumbersに保持します。
+ // これによりソートしてもコミュニケータランクを失いません。
+ CommRankNumber *comm_rank_numbers = malloc(
+ gathered_number_count * sizeof(CommRankNumber));
+ int i;
+ for (i = 0; i < gathered_number_count; i++) {
+ comm_rank_numbers[i].comm_rank = i;
+ memcpy(&(comm_rank_numbers[i].number),
+ gathered_numbers + (i * datatype_size),
+ datatype_size);
+ }
+
+ // ランクの情報を持ったまま値をソートする
+ if (datatype == MPI_FLOAT) {
+ qsort(comm_rank_numbers, gathered_number_count,
+ sizeof(CommRankNumber), &compare_float_comm_rank_number);
+ } else {
+ qsort(comm_rank_numbers, gathered_number_count,
+ sizeof(CommRankNumber), &compare_int_comm_rank_number);
+ }
+
+ // ソートが完了したので値を戻すための結果の配列を用意する。iにはプロセスiの順位が含まれる。
+ int *ranks = (int *)malloc(sizeof(int) * gathered_number_count);
+ for (i = 0; i < gathered_number_count; i++) {
+ ranks[comm_rank_numbers[i].comm_rank] = i;
+ }
+
+ // comm_rank_numbersを解放する
+ free(comm_rank_numbers);
+ return ranks;
+}
+```
+`get_ranks`は`CommRankNumber`構造体の配列を作成して、各プロセスのランクを設定します。`MPI_FLOAT`と`MPI_INT`である場合で違ったsort関数の呼び出しを行います。 ([tmpi_rank.c]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c)を参照してください)。
+
+ソートしたら順番を格納した配列を作成して各々のプロセスに正しく戻せるようにする必要があります。ソートされた`comm_rank_numbers`を順に見ていき、戻すための配列`ranks`を作ります。
+
+## 全てを一緒にする - Putting it all together
+さて、2つの重要なルーチンが実装できたのでこれらをまとめて `TMPI_Rank` を作りましょう。ルートプロセスに各プロセスの数字を集めてから、計算した順位を各プロセスに戻します。このコードを以下に示します。
+```cpp
+// datatype型のsend_dataの順位を取得する。
+// ランクはrecv_dataで戻ってくるdatatype型である。
+int TMPI_Rank(void *send_data, void *recv_data, MPI_Datatype datatype,
+ MPI_Comm comm) {
+ // datatypeがMPI_INTかMPI_FLOATであるかを確認します
+ if (datatype != MPI_INT && datatype != MPI_FLOAT) {
+ return MPI_ERR_TYPE;
+ }
+
+ int comm_size, comm_rank;
+ MPI_Comm_size(comm, &comm_size);
+ MPI_Comm_rank(comm, &comm_rank);
+
+ // 順位を計算するために値をルートプロセスに集めます。
+ // そして、ソートして結果を求め、Scatterで順位情報を戻します。
+ // ルートプロセスにはプロセス0を使います
+ void *gathered_numbers = gather_numbers_to_root(send_data, datatype,
+ comm);
+
+ // 各プロセスの順位を計算する
+ int *ranks = NULL;
+ if (comm_rank == 0) {
+ ranks = get_ranks(gathered_numbers, comm_size, datatype);
+ }
+
+ // Scatterする
+ MPI_Scatter(ranks, 1, MPI_INT, recv_data, 1, MPI_INT, 0, comm);
+
+ // clean up
+ if (comm_rank == 0) {
+ free(gathered_numbers);
+ free(ranks);
+ }
+}
+```
+
+TMPI_Rank関数は`gather_numbers_to_root`と`get_ranks`の2つの関数を使用して各の順位を計算します。この関数は`MPI_Scatter`によって各プロセスに順位を戻します。
+
+全体のデータフローを図解します。
+
+
+
+もし、これに関する質問があれば以下を参照して質問してください。
+
+## 実行 - Running our parallel rank algorithm
+このアルゴリズムのサンプルプログラムがあります。[レッスンコード]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code)の[random_rank.c file]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code/random_rank.c)で確認できます。
+
+このサンプルプログラムは各プロセスで乱数を生成した後、各順位を取得するために`TMPI_Rank`の呼び出しします。[レポジトリ]({{ site.github.code }})のチュートリアルディレクトリから random_rank プログラムを実行すると、出力は次のようになります。
+
+```
+>>> cd tutorials
+>>> ./run.py random_rank
+mpirun -n 4 ./random_rank 100
+Rank for 0.242578 on process 0 - 0
+Rank for 0.894732 on process 1 - 3
+Rank for 0.789463 on process 2 - 2
+Rank for 0.684195 on process 3 - 1
+```
+
+## Up next
+次はさらに高度な集団通信について説明します。次のレッスンは、[using MPI_Reduce and MPI_Allreduce to perform number reduction]({{ site.baseurl }}/tutorials/mpi-reduce-and-allreduce/)です。
+
+[MPI tutorials]({{ site.baseurl }}/tutorials/) に全てのレッスンの目次があります。
\ No newline at end of file
diff --git a/tutorials/performing-parallel-rank-with-mpi/zh_cn.md b/tutorials/performing-parallel-rank-with-mpi/zh_cn.md
index bfa4828..4145f9d 100644
--- a/tutorials/performing-parallel-rank-with-mpi/zh_cn.md
+++ b/tutorials/performing-parallel-rank-with-mpi/zh_cn.md
@@ -136,7 +136,7 @@ int *get_ranks(void *gathered_numbers, int gathered_number_count,
}
```
-`get_ranks` 函数首先创建一个CommRankNumber结构体数组,并附上该数字所属进程在通讯器中的次序。 如果数据类型为 `MPI_FLOAT` ,则对我们的结构体数组调用 `qsort` 时,会使用特殊的排序函数,(代码见[tmpi_rank.c]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code)。 类似的,如果数据类型为 `MPI_INT` ,我们将使用不同的排序函数。
+`get_ranks` 函数首先创建一个CommRankNumber结构体数组,并附上该数字所属进程在通讯器中的次序。 如果数据类型为 `MPI_FLOAT` ,则对我们的结构体数组调用 `qsort` 时,会使用特殊的排序函数,(代码见[tmpi_rank.c]({{ site.github.code }}/tutorials/performing-parallel-rank-with-mpi/code/tmpi_rank.c)。 类似的,如果数据类型为 `MPI_INT` ,我们将使用不同的排序函数。
在对数字进行排序之后,我们必须以适当的顺序创建一个排名数组(array of ranks),以便将它们分散(scatter)回到请求的进程中。这是通过创建 `ranks` 数组并为每个已排序的 `CommRankNumber` 结构体填充适当的排名来实现的。
@@ -144,8 +144,8 @@ int *get_ranks(void *gathered_numbers, int gathered_number_count,
现在我们有了两个主要函数,我们可以将它们全部整合到我们的 `TMPI_Rank` 函数中。此函数将数字收集到根进程,并对数字进行排序以确定其排名,然后将排名分散回请求的进程。 代码如下所示:
```cpp
-// 获取recv_data的排名, 类型为datatype
-// 排名用send_data返回,类型为datatype
+// 获取send_data的排名, 类型为datatype
+// 排名用recv_data返回,类型为datatype
int TMPI_Rank(void *send_data, void *recv_data, MPI_Datatype datatype,
MPI_Comm comm) {
// 首先检查基本情况 - 此函数只支持MPI_INT和MPI_FLOAT
diff --git a/tutorials/point-to-point-communication-application-random-walk/index.md b/tutorials/point-to-point-communication-application-random-walk/index.md
index db510f3..371da4f 100644
--- a/tutorials/point-to-point-communication-application-random-walk/index.md
+++ b/tutorials/point-to-point-communication-application-random-walk/index.md
@@ -4,7 +4,7 @@ title: Point-to-Point Communication Application - Random Walk
author: Wes Kendall
categories: Beginner MPI
tags:
-translations: zh_cn
+translations: zh_cn,ja_jp
redirect_from: '/point-to-point-communication-application-random-walk/'
---
diff --git a/tutorials/point-to-point-communication-application-random-walk/ja_jp.md b/tutorials/point-to-point-communication-application-random-walk/ja_jp.md
new file mode 100644
index 0000000..61bd01e
--- /dev/null
+++ b/tutorials/point-to-point-communication-application-random-walk/ja_jp.md
@@ -0,0 +1,302 @@
+---
+layout: post
+title: ポイントツーポイント通信アプリケーション ランダムウォーク - Point-to-Point Communication Application - Random Walk
+author: Wes Kendall
+categories: Beginner MPI
+tags:
+redirect_from: '/point-to-point-communication-application-random-walk/'
+---
+
+[sending and receiving tutorial]({{ site.baseurl }}/tutorials/mpi-send-and-receive/)と[MPI_Probe and MPI_Status lesson]({{ site.baseurl }}/tutorials/dynamic-receiving-with-mpi-probe-and-mpi-status/) の レッスンで紹介された概念のいくつかを使用して実際のアプリケーションを作成しましょう。これは「ランダムウォーク」と呼ばれるシミュレートションです。
+
+
+> **Note** - このサイトのコードはすべて[GitHub]({{ site.github.repo }})にあります。このレッスンのコードは[tutorials/point-to-point-communication-application-random-walk/code]({{ site.github.code }}/tutorials/point-to-point-communication-application-random-walk/code)にあります。
+
+ランダムウォークの問題設定を説明します。この問題ではある数直線の*Min*、*Max*とおよびランダムウォーカー*W*が与えられます。ウォーカー*W*は適当なの長さのランダムウォークを右に*S*回実行します。右端に到達したら、プロセスは左端に戻ります(訳注: If the process goes out of bounds, it wraps back around. で折り返すとあるが、スタートに戻る実装です)。*W*は一度に右か1ユニットしか移動できません(訳注: to the right or left at a timeとありますが、右にだけ動く実装です)。
+
+
+
+この動作はとても基本的ですが、ランダムウォークの並列化というのはさまざまな並列アプリケーションのシミュレートで用いられる手法です。このことは最後に詳しく説明します。まずは、ランダムウォークの問題を並列化する方法を考えます。
+
+## ランダムウォーキング問題の並列化 - Parallelization of the random walking problem
+多くの並列プログラミングにとって最初に考えなければいけないのは、各プロセスがが持つ領域の分割です。ランダムウォークは*Max - Min + 1* の大きさの1次元の領域を考えます(*Max*と*Min*は含まれて良い値です)。ウォーカーのステップを整数とて考えると、各領域をほぼ等しいサイズに分割することができるでしょう。例えば*Min*が0、*Max*が20で、分割するプロセスが4つの場合はドメインを次のように分割できます。
+
+
+
+最初の3プロセス(プロセス0,1,2)は5つのユニットを管理します。最後のプロセス3は合計6つのユニットを管理します。これは、同じように分割された5つのユニットに加えて残りの1つのユニットです。ドメインを分割したらアプリケーションはウォーカーを初期化します。ウォーカーはランダムなウォークサイズでS回のウォークを実行します。今説明した分割においてウォーカーがプロセス0からサイズ6のウォークを実行すると次のようになります。(訳注:サイズ6のウォークとは、6ユニット移動する動作です)
+
+1. プロセス0からウォーカーは6のステップします。値が4になった時プロセス0の境界に達しています。プロセス0はプロセス1にウォーカーを渡します。
+
+2. プロセス1はウォーカーを受け取ったあと、合計が6に達するまでウォークを続けます。このサイクルを1つとしてウォーカーは新しいランダムウォークを試行します。
+
+
+
+*W*はプロセス0からプロセス1に1回だけ移動しましたが*W*がさらに長い距離を移動する時はドメイン内のより多くのプロセスを通過する必要がある可能性があります。
+
+## CMPI_Send と MPI_Recv を使用したコーディング - oding the application using MPI_Send and MPI_Recv
+この動作を`MPI_Send` と`MPI_Recv`を使用して書いていきましょう。まず、前にプログラムの動きを整理します。
+
+* プロセスはドメイン内の自分の領域を識別します
+* 各プロセスは*N*個のウォーカーを初期化します。これらはすべてそのプロセスの最初の値から開始されます。(訳注: 5-9を管理するプロセスであれば、このプロセスに割り当てられた全てのウォーカーは5にいることにします)
+* 各ウォーカーはオブジェクトです。ウォーカーの現在位置と残歩数という 2 つのintを持ちます。
+* ウォーカーたちはドメイン内でウォークを開始し、ウォークを完了するまで他のプロセスへの移動を行います。
+* すべてのウォーカーが終了するとそのターンは終了します。
+
+まずはプロセスが領域を分割するコードを書きます。この関数はドメインの合計サイズを受け取りMPIプロセスが担当する適切なサイズの分割された領域を決定します。そして残ってしまった領域を最後のプロセスに担当させます。簡単のためエラーが見つかった場合は`MPI_Abort`を呼び出すことにします。この関数`decompose_domain`を示します。
+
+```cpp
+void decompose_domain(int domain_size, int world_rank,
+ int world_size, int* subdomain_start,
+ int* subdomain_size) {
+ if (world_size > domain_size) {
+ // 領域の数が用意できるプロセスの数より大きいならエラーとします
+ MPI_Abort(MPI_COMM_WORLD, 1);
+ }
+ *subdomain_start = domain_size / world_size * world_rank;
+ *subdomain_size = domain_size / world_size;
+ if (world_rank == world_size - 1) {
+ // 残りを最後のプロセスに割り当てます
+ *subdomain_size += domain_size % world_size;
+ }
+ }
+```
+
+関数は余りがある場合を配慮しながらドメインを均等な領域に分割します。そして関数はその領域の開始位置とサブドメインのサイズを返します。
+
+ウォーカーは次の構造体で定義します。
+
+```cpp
+typedef struct {
+ int location;
+ int num_steps_left_in_walk;
+} Walker;
+```
+
+次に`initialize_walkers`という初期化関数を考えます。この関数はそのプロセスの領域を取得し、そのプロセスが担当するウォーカーを配列`incoming_walkers`に追加します (このアプリケーションは C++ で書かれています)。
+
+```cpp
+void initialize_walkers(int num_walkers_per_proc, int max_walk_size,
+ int subdomain_start, int subdomain_size,
+ vector* incoming_walkers) {
+ Walker walker;
+ for (int i = 0; i < num_walkers_per_proc; i++) {
+ // Initialize walkers in the middle of the subdomain
+ // 訳注: "in the mid"とあるが、ウォーカーは領域の最初から開始する
+ walker.location = subdomain_start;
+ walker.num_steps_left_in_walk =
+ (rand() / (float)RAND_MAX) * max_walk_size;
+ incoming_walkers->push_back(walker);
+ }
+}
+```
+
+初期化の次はウォーカーを前進させる関数です。この関数はウォーカーが歩行を完了するまで前進させます。ウォーカーが自分の管理する領域の端より進もうとしたら、そのプロセスの配列`outgoing_walkers`に追加します。
+
+```cpp
+void walk(Walker* walker, int subdomain_start, int subdomain_size,
+ int domain_size, vector* outgoing_walkers) {
+ while (walker->num_steps_left_in_walk > 0) {
+ if (walker->location == subdomain_start + subdomain_size) {
+ // Take care of the case when the walker is at the end
+ // of the domain by wrapping it around to the beginning
+ if (walker->location == domain_size) {
+ walker->location = 0;
+ }
+ outgoing_walkers->push_back(*walker);
+ break;
+ } else {
+ walker->num_steps_left_in_walk--;
+ walker->location++;
+ }
+ }
+}
+```
+
+初期化関数 (`incoming_walkers`にデータを追加する) とウォーキング関数 (`outgoing_walkers`にデータを追加する)ができたので、あとは`outgoing_walkers`を次のプロセスに送る関数と受け取る関数の2つがあれば良いです。まずは`outgoing_walkers`を次に送る関数を見ていきます。
+
+```cpp
+void send_outgoing_walkers(vector* outgoing_walkers,
+ int world_rank, int world_size) {
+ // 配列のデータをMPI_BYTEsのバイトデータとして次のプロセスに送ります
+ // 右端のプロセスはプロセス0にデータを送ることに注意します
+ MPI_Send((void*)outgoing_walkers->data(),
+ outgoing_walkers->size() * sizeof(Walker), MPI_BYTE,
+ (world_rank + 1) % world_size, 0, MPI_COMM_WORLD);
+
+ // 次のプロセスにデータを送ったので配列はクリアします
+ outgoing_walkers->clear();
+}
+```
+
+次は受け取る関数です。受け取るウォーカーの数が事前にわからないため`MPI_Probe`を使用する必要があります。
+
+```cpp
+void receive_incoming_walkers(vector* incoming_walkers,
+ int world_rank, int world_size) {
+ MPI_Status status;
+
+ // 前のプロセスからのデータを受け取ります
+ // プロセス0は右端のプロセスからのデータを受け取ります
+ int incoming_rank =
+ (world_rank == 0) ? world_size - 1 : world_rank - 1;
+ MPI_Probe(incoming_rank, 0, MPI_COMM_WORLD, &status);
+
+ // そして受け取るべきデータのサイズ分のメモリを確保します
+ int incoming_walkers_size;
+ MPI_Get_count(&status, MPI_BYTE, &incoming_walkers_size);
+ incoming_walkers->resize(
+ incoming_walkers_size / sizeof(Walker));
+ MPI_Recv((void*)incoming_walkers->data(), incoming_walkers_size,
+ MPI_BYTE, incoming_rank, 0, MPI_COMM_WORLD,
+ MPI_STATUS_IGNORE);
+}
+```
+
+これでプログラムの主な機能を実装しました。次のように処理を作っていきましょう。
+
+1. ウォーカーを初期化する。
+2. `walk` 関数でウォーカーを進める。
+3. `outgoing_walkers`にあるウォーカーを次に送る
+4. 新しいウォーカーは`incoming_walkers`に入れる。
+5. すべてのウォーカーが終了するまで、ステップ2から4を繰り返す。
+
+以下の通りとなるが、まずは5で行いたいすべてのウォーカーの終了判定は気にしないものとします。このコードには誤りがあるのでそれに留意してご覧ください。
+
+```cpp
+// このプロセスの領域を決める
+decompose_domain(domain_size, world_rank, world_size,
+ &subdomain_start, &subdomain_size);
+
+// このプロセスのウォーカーを配置する(incoming_walksに入れる)
+initialize_walkers(num_walkers_per_proc, max_walk_size,
+ subdomain_start, subdomain_size,
+ &incoming_walkers);
+
+while (!all_walkers_finished) { // 全てのウォーカーが終了するまで
+ // このプロセス内全てのウォーカーの動きを実施
+ for (int i = 0; i < incoming_walkers.size(); i++) {
+ walk(&incoming_walkers[i], subdomain_start, subdomain_size,
+ domain_size, &outgoing_walkers);
+ }
+
+ // 外に出ていくウォーカーの処理
+ send_outgoing_walkers(&outgoing_walkers, world_rank,
+ world_size);
+
+ // 新しく入ってきたウォーカーの処理
+ receive_incoming_walkers(&incoming_walkers, world_rank,
+ world_size);
+}
+```
+
+良さそうに見えますか?しかし、これはデッドロックが起こりやすいコードとなっています。
+
+## デッドロックとその予防方法 - Deadlock and prevention
+Wikipediaによれば、デッドロックとは「2つ以上のプロセスがそれぞれ他のプロセスのリソース解放を待つ。あるいは2つ以上のプロセスが循環的にリソースを待っている。こういった特定の状態のこと」です。上記のコードは`MPI_Send`の循環的なチェーンが発生します。
+
+
+
+とはいえ、実施には上記コードはデッドロックはほぼ発生*しません*。`MPI_Send`はブロッキング関数ですが、[MPI specification](http://www.amazon.com/gp/product/0262692163/ref=as_li_tf_tl?ie=UTF8&tag=softengiintet-20&linkCode=as2&camp=217145&creative=399377&creativeASIN=0262692163)では、`MPI_Send` は*送信バッファが確保できるまで*ブロックすると記載されています。MPI_Sendはネットワークがメッセージをバッファできるようになったときにブロッキングが終わります。つまりネットワークがバッファできなければそれに対応するreceiveが呼ばれるまでsendはブロックされるということです。今回のケースでは非常に小さな送信に対して非常に頻繁に受信を呼び出すコードであるためデッドロックはほぼないでしょう。しかし、全てのケースでネットワークバッファが十分に大きいと想定して並列プログラミングを書いてはいけません。
+
+このレッスンでは `MPI_Send` と `MPI_Recv` だけに焦点をあてています。送受信のデッドロックを回避するベストの方法は送信と受信が一致するようにメッセージングを順序付けることです。いくつかの方法が考えられますが、1つとしては偶数番目のプロセスが受信の前に送信を送り、奇数番目のプロセスがその逆を行うようにすることです。もし、2つの実行ステージで考えると次のようなイメージとなります。
+
+
+
+> **Note** - これを1プロセスの環境下で実行するとデッドロックが発生する例外があります。
+
+奇数個のプロセスでもこれは機能するのでしょうか?3つのプロセスで同様の図をもう一度見てみましょう。
+
+
+
+3つのパターン全てにおいて、少なくとも1つの`MPI_Send`と`MPI_Recv`が存在するパスがあるので、デッドロックの発生を心配する必要はないとわかりました。
+
+## 終了の判断 - Determining completion of all walkers
+それでは、すべてのウォーカーが終了したかを判断するステップを考えます。ウォーカーはランダムな距離をいどうするため、あるウォーカーが移動を終了することは全てのプロセスで起こり得ることに注意します。そのため、何らかの追加通信を行わずに全プロセスがすべての歩行者が終了を知ることは困難です。考えられる解決策の1つはプロセス0がすべての歩行者を追跡し、他のすべてのプロセスに終了を伝えることが考えられます。ただし、この解決策は各移動においてプロセス0以外のプロセスはプロセス0に完了した歩行者を報告し、さらにさまざまな種類の受信メッセージを処理する必要があるため非常に面倒ですね。
+
+このレッスンではもっとシンプルに考えます。どのウォーカーも移動できる最大距離と、ある送受信のプロセスのペアで移動できる最小の合計サイズ(サブドメインのサイズ)がわかっています。このため、各プロセスが終了までに行うべき送受信の量が定まります(訳注:全てのプロセスが最大の距離を行うとき、というのがこれに当てはまります)。この特徴とデッドロックを回避する戦略を用いると以下のように考えられます。
+
+```cpp
+// このプロセスの領域を決める
+decompose_domain(domain_size, world_rank, world_size,
+ &subdomain_start, &subdomain_size);
+
+// このプロセスのウォーカーを配置する(incoming_walksに入れる)
+initialize_walkers(num_walkers_per_proc, max_walk_size,
+ subdomain_start, subdomain_size,
+ &incoming_walkers);
+
+// 全てのウォーカーが終了するのに必要なsend/recv数を計算
+int maximum_sends_recvs =
+ max_walk_size / (domain_size / world_size) + 1;
+for (int m = 0; m < maximum_sends_recvs; m++) {
+ // このプロセス内全てのウォーカーの動きを実施
+ for (int i = 0; i < incoming_walkers.size(); i++) {
+ walk(&incoming_walkers[i], subdomain_start, subdomain_size,
+ domain_size, &outgoing_walkers);
+ }
+
+ // 偶数・奇数に基づいた順序で送受信を行う
+ if (world_rank % 2 == 0) {
+ send_outgoing_walkers(&outgoing_walkers, world_rank,
+ world_size);
+ receive_incoming_walkers(&incoming_walkers, world_rank,
+ world_size);
+ } else {
+ receive_incoming_walkers(&incoming_walkers, world_rank,
+ world_size);
+ send_outgoing_walkers(&outgoing_walkers, world_rank,
+ world_size);
+ }
+}
+```
+
+## Running the application
+
+レッスンのコードは[ここ]({{ site.github.code }}/tutorials/point-to-point-communication-application-random-walk/code)で見ることができます. 他のレッスンとは異なり、このコードはC++を使用しています。[installing MPICH2]({{ site.baseurl }}/tutorials/installing-mpich2/)の際に、C++ MPIコンパイラもインストールしました(明示的に設定した場合を除く)。MPICH2をローカル・ディレクトリにインストールした場合はMPICXX環境変数が正しいmpicxxコンパイラーを指すように設定されていることを確認してください。
+
+私のコードでは、アプリケーションの実行スクリプトにプログラムのデフォルト値を設定しています。ドメインサイズは 100、最大ウォークサイズは 500、プロセスあたりのウォーカー数は 20 です。random_walkプログラムを[レポジトリ]({{ site.github.code }})の*tutorials*ディレクトリから実行すると、5つのプロセスが生成され、このような出力が得られます。
+
+```
+>>> cd tutorials
+>>> ./run.py random_walk
+mpirun -n 5 ./random_walk 100 500 20
+Process 2 initiated 20 walkers in subdomain 40 - 59
+Process 2 sending 18 outgoing walkers to process 3
+Process 3 initiated 20 walkers in subdomain 60 - 79
+Process 3 sending 20 outgoing walkers to process 4
+Process 3 received 18 incoming walkers
+Process 3 sending 18 outgoing walkers to process 4
+Process 4 initiated 20 walkers in subdomain 80 - 99
+Process 4 sending 18 outgoing walkers to process 0
+Process 0 initiated 20 walkers in subdomain 0 - 19
+Process 0 sending 17 outgoing walkers to process 1
+Process 0 received 18 incoming walkers
+Process 0 sending 16 outgoing walkers to process 1
+Process 0 received 20 incoming walkers
+```
+
+プロセスはすべてのウォーカーの送受信を終える(と想定される回数)まで出力を続けます。
+
+## So what's next?
+いかがでしょうか。もしこのレッスンを心地よいと感じたなら良いことです。このアプリケーションは、初めての実際のアプリケーションとしてはかなり発展的なものです。
+
+次回のレッスンからはMPIでの*集団通信*について学習します。まず、[MPI Broadcast]({{ site.baseurl }}/tutorials/mpi-broadcast-and-collective-communication/)を学習します。その他のレッスンは[MPI tutorials]({{ site.baseurl }}/tutorials/)をみてください。
+
+冒頭で、このプログラムのコンセプト(ランダムウォーク)は多くの並列プログラムにも応用できることをお伝えしました。もっと学びたい人のために、以下に追加資料を掲載したのでお楽しみください :-)
+
+## 追加資料 - ランダムウォーキングと並列粒子追跡の類似性 Additional reading - Random walking and its similarity to parallel particle tracing
+ランダムウォーク問題は、一見単純なものに見えますが実は多くの種類の並列アプリケーションのシミュレーションの基礎となります。科学分野の一部の並列アプリケーションでは、多くの種類のランダムな送受信が必要です。1つのアプリケーション例は並列粒子追跡(parallel particle tracing)です。
+
+
+
+並列粒子追跡は流れ場を可視化するための主要な手法の1つです。粒子を流れ場に仮定して数値積分技術(Runge-Kutta法など)を用いて流れに沿って追跡します。この経路は、可視化のために描画することができます。描画の一例として上のトルネード画像があります。
+
+効率的な並列粒子追跡というのは非常に困難しいです。主な理由は粒子の移動方向が積分の各増分ステップの後にしか決定できないためです。したがってプロセスがすべての通信と計算を調整してバランスをとるのは困難です。より理解するために、粒子追跡の一般的な並列化を見てみましょう。
+
+
+
+この図はドメインを6つのプロセスに分割していることがわかります。粒子(時にはシードと呼ばれる)が各サブドメインに配置され(ウォーカーをそれぞれの領域に配置した方法に似ています)、その後トレースを開始します。粒子が境界を越えると、適切なサブドメインを持つプロセスと情報を交換します。このプロセスは粒子が領域から離れるか最大トレースの回数に達するまで繰り返されます。
+
+並列粒子追跡の問題は、先ほどコーディングしたアプリケーションと同様に`MPI_Send`、`MPI_Recv`、`MPI_Probe`を使用して解決できます。より効率的に作業を行うために、もっと洗練されたMPIルーチンも存在するのでそれは次のレッスンでお話しします :-)
+
+ランダムウォークの問題が他の並列アプリケーションとどのように似ているかを示す例を少なくとも1つは確認できたと思います。
\ No newline at end of file
diff --git a/tutorials/point-to-point-communication-application-random-walk/zh_cn.md b/tutorials/point-to-point-communication-application-random-walk/zh_cn.md
index 687a93f..be29600 100644
--- a/tutorials/point-to-point-communication-application-random-walk/zh_cn.md
+++ b/tutorials/point-to-point-communication-application-random-walk/zh_cn.md
@@ -95,7 +95,7 @@ typedef struct {
```
我们的初始化函数为 `initialize_walkers`,它采用子域边界,并将 walker 添加到 `incoming_walkers` `vector` 中(顺便说一下,该程序采用 C++)。
-Our initialization function, called `initialize_walkers`, takes the subdomain bounds and adds walkers to an `incoming_walkers` vector (by the way, this application is in C++).
+
```cpp
void initialize_walkers(int num_walkers_per_proc, int max_walk_size,
@@ -230,7 +230,6 @@ while (!all_walkers_finished) { // Determine walker completion later

值得注意的是,上面的代码在大多数情况下实际上不会“死锁”。
-It is worth noting that the above code will actually **not** deadlock most of the time.
尽管 `MPI_Send` 是一个阻塞调用,但是 [MPI 规范](http://www.amazon.com/gp/product/0262692163/ref=as_li_tf_tl?ie=UTF8&tag=softengiintet-20&linkCode=as2&camp=217145&creative=399377&creativeASIN=0262692163) 表明 `MPI_Send` 会一直阻塞,直到可以**回收发送缓冲区为止**。
这意味着当网络可以缓冲消息时,`MPI_Send` 将返回。
如果发送最终无法被网络缓冲,它们将一直阻塞直到发布匹配的接收。
diff --git a/tutorials/run.py b/tutorials/run.py
index 4e90a32..2215481 100755
--- a/tutorials/run.py
+++ b/tutorials/run.py
@@ -37,8 +37,8 @@
'reduce_stddev': ('mpi-reduce-and-allreduce', 4, ['100']),
# From the groups-and-communicators tutorial
- 'split': ('introduction-to-groups-and-communicators', 16),
- 'groups': ('introduction-to-groups-and-communicators', 16)
+ 'comm_split': ('introduction-to-groups-and-communicators', 16),
+ 'comm_groups': ('introduction-to-groups-and-communicators', 16)
}
program_to_run = sys.argv[1] if len(sys.argv) > 1 else None
diff --git a/tutorials/running-an-mpi-cluster-within-a-lan/index.md b/tutorials/running-an-mpi-cluster-within-a-lan/index.md
index 6992bba..79e9175 100644
--- a/tutorials/running-an-mpi-cluster-within-a-lan/index.md
+++ b/tutorials/running-an-mpi-cluster-within-a-lan/index.md
@@ -3,6 +3,7 @@ layout: post
title: Running an MPI Cluster within a LAN
author: Dwaraka Nath
categories: Beginner MPI
+translations: ja_jp
tags: MPI, Cluster, LAN
redirect_from: '/running-an-mpi-cluster-within-a-lan'
---
@@ -238,7 +239,7 @@ $ cat /etc/hosts
To make this more clear, from ```manager``` node, this script can be invoked.
```bash
-$ mpirun -np 10 --hosts manager./cpi
+$ mpirun -np 10 --hosts manager ./cpi
# To run the program only on the same manager node
```
diff --git a/tutorials/running-an-mpi-cluster-within-a-lan/ja_jp.md b/tutorials/running-an-mpi-cluster-within-a-lan/ja_jp.md
new file mode 100644
index 0000000..5c6978a
--- /dev/null
+++ b/tutorials/running-an-mpi-cluster-within-a-lan/ja_jp.md
@@ -0,0 +1,262 @@
+---
+layout: post
+title: LAN上でのMPIクラスタ構築 - Running an MPI Cluster within a LAN
+author: Dwaraka Nath
+categories: Beginner MPI
+tags: MPI, Cluster, LAN
+redirect_from: '/running-an-mpi-cluster-within-a-lan'
+---
+
+先のレッスンではMPIプログラムを[1台のマシン]({{ site.baseurl }}/tutorialss/mpi-hello-world/)で実行し、CPUに1つ以上のコアがある利点を生かしてコードを並列処理することを見てきました。それでは同じことを1台のコンピュータではなく、LANに接続されたノードで実行できるようにしましょう。物事を単純にするために、このレッスンでは2台のコンピュータを考えます。ノードをもっと増やすのは同じようにできます。
+
+他のチュートリアルと同様にLinuxマシンを使用することを前提としています。以下のチュートリアルはUbuntuでテストしましたが、他のディストリビューションでも同じはずです。また、あなたの2台のマシンを**管理者(manager)**とし、もう1台を**作業者(worker)**と呼ぶとしましょう。
+
+## 前提
+
+すべてのマシンにMPICH2をインストールしていない場合は、[この手順]({{ site.baseurl }}/tutorials/installing-mpich2/)を実行してください。
+
+## Step 1: `hosts`の準備 - Configure your ```hosts``` file
+
+`hosts`を用意しましょう。これはマシンのオペレーティングシステムがホスト名をIPアドレスにマッピングするために使用します。以下に例を示します。
+
+```bash
+
+$ cat /etc/hosts
+
+127.0.0.1 localhost
+172.50.88.34 worker
+```
+これは`Manager`の`hosts`で、`worker`は、あなたが計算を行いたい他のマシン名です。同様に、Workerでは`manager`も同じようにします。
+
+## Step 2: ユーザの作成 - Create a new user
+
+既存のユーザーアカウントでクラスタを操作することもできます。しかし、設定をシンプルにするために新しいユーザーアカウントを作成することをお勧めします。全てのホストでユーザー`mpiuser`を作成しましょう。
+
+```bash
+$ sudo adduser mpiuser
+```
+プロンプトに従ってください。`adduser`ではなく`useradd`コマンドを使ってしまうとホームディレクトリが作成されないので使用しないでください。
+
+## Step 3: SSHの設定 - Setting up SSH
+
+マシン間が通信できるようにSSHの設定をします。[NFS](#step-4-setting-up-nfs)を使ってデータを共有します。
+```bash
+$ sudo apt-get install openssh-server
+```
+
+まず、このホストでユーザをmpiuserに切り替えます。
+
+```bash
+$ su - mpiuser
+```
+すでに `ssh` サーバーがインストールされているので、他のマシンに `ssh username@hostname` でログインできるはずです。パスワードを尋ねられないようにキーを生成して他のマシンの ``authorized_keys`` のリストにコピーします。(訳注:この処理は公開鍵認証を可能にする、という処理です。パスワード認証を禁止してはいないことに注意してください)
+
+```bash
+$ ssh-keygen -t dsa
+```
+
+この例ではDSA鍵を作成しましたがRSA鍵を生成することもできます。より高いセキュリティを求めるのであれば、RSAを使っても良いですがDSAでも十分です。そして、生成した鍵を他のコンピューターに追加すしましょう。wokerノードに対してコピーします。
+
+```bash
+$ ssh-copy-id worker #ip-address may also be used
+```
+
+それぞれのWorkerマシンと自分のユーザ (localhost) に対してここまでの手順を実行してください。
+
+これで `openssh-server` がセットアップされ、Workerと安全に通信できるようになります。すべてのマシンに一度 `ssh` を実行してください。そして`known_hosts` のリストに他のホストのフィンガープリントを追加します。このステップは`ssh`ログインのトラブルになりやすいので重要なステップです。
+
+パスワードなしの sshができるようにしましょう。
+
+```bash
+$ eval `ssh-agent`
+$ ssh-add ~/.ssh/id_dsa
+```
+さてパスワードのプロンプトなしで他のマシンにログインできるはずです。
+
+```bash
+$ ssh worker
+```
+
+> **Note** - すべてのワーカーマシンで共通のユーザアカウントとして `mpiuser` を作成したと仮定しています。ManagerとWorkerで異なる名前のユーザーアカウントを作成した場合は適切なユーザ名を指定してください。
+
+## Step 4: NFSの設定 - Setting up NFS
+
+**manager**はNFS経由でディレクトリを共有し、それを**worker**がマウントしてデータをやり取りします。
+
+### NFS-Server
+
+パッケージをインストールします。
+
+```bash
+$ sudo apt-get install nfs-kernel-server
+```
+
+まだ `mpiuser` にログインしていると仮定して `cloud` という名前の共有フォルダを作成します。
+
+```bash
+$ mkdir cloud
+```
+
+`cloud`を共有するために`/etc/exports`を以下のようにします。
+
+```bash
+$ cat /etc/exports
+/home/mpiuser/cloud *(rw,sync,no_root_squash,no_subtree_check)
+```
+`*`の部分にはこのフォルダを共有したいIPアドレスを指定することができますが。今回は簡単のため`*`にしています。
+
+* **rw**: read/writeを許可します。readのみを割り当てたいなら **ro**を設定します。
+* **sync**: 変更をコミットした後にのみ、共有ディレクトリに変更を適用されます
+* **no_subtree_check**: サブツリーをチェックしません。共有ディレクトリが大きなファイルシステムのサブディレクトリである場合、 nfsはその上のすべてのディレクトリのパーミッションと詳細を確認するために スキャンを実行します。サブツリー・チェックを無効にするとNFSの信頼性は向上しますがセキュリティが低下することがあります。
+* **no_root_squash**: rootアカウントによるフォルダへの接続を許可します。
+
+> この説明を作るために[Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nfs-mount-on-ubuntu-12-04)を参考にしました. このライセンスはCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International Licenseに従います。このライセンスの詳細は [ここ](https://creativecommons.org/licenses/by-nc-sa/4.0/)です。
+
+NFSを実行します。
+
+```bash
+$ exportfs -a
+```
+
+`/etc/exports` に変更を加えた場合はこのコマンドが必要です。
+
+必要に応じて`nfs` サーバを再起動してください。
+
+```bash
+$ sudo service nfs-kernel-server restart
+```
+
+### NFS-worker
+
+以下を実行します。
+
+```bash
+$ sudo apt-get install nfs-common
+```
+
+workerで同じ名前のディレクトリを作成します。
+
+```bash
+$ mkdir cloud
+```
+
+そして次のように共有ディレクトリをマウントしてください。
+
+```bash
+$ sudo mount -t nfs manager:/home/mpiuser/cloud ~/cloud
+```
+
+正常にマウントできたか確認しましょう。
+
+```bash
+$ df -h
+Filesystem Size Used Avail Use% Mounted on
+manager:/home/mpiuser/cloud 49G 15G 32G 32% /home/mpiuser/cloud
+```
+
+再起動のために手動で共有ディレクトリをマウントする必要がないようにするには ``/etc/fstab`` ファイルに次のようなエントリを作成してください。
+
+```bash
+$ cat /etc/fstab
+#MPI CLUSTER SETUP
+manager:/home/mpiuser/cloud /home/mpiuser/cloud nfs
+```
+
+## Step 5: MPIプログラムの実行 - Running MPI programs
+
+それでは正常性の確認のため、MPICH2のインストールパッケージ `mpich2/examples/cpi` に付属しているサンプルプログラムを並列実行してみましょう。
+
+自分のコードをコンパイルしたい場合は、コードを`mpi_sample.c` とすると、以下に示す方法でコンパイルして ``mpi_sample`` を生成できます。
+
+
+```bash
+$ mpicc -o mpi_sample mpi_sample.c
+```
+
+そして実行ファイルを共有ディレクトリ `cloud` にコピーしてください。もちろん、NFS 共有ディレクトリ内でコードをコンパイルしても良いです。
+
+```bash
+$ cd cloud/
+$ pwd
+/home/mpiuser/cloud
+```
+
+自分のマシン(manager)だけで実行するときは以下のようにします。
+
+```bash
+$ mpirun -np 2 ./cpi # No. of processes = 2
+```
+
+クラスタで実行してみましょう。
+
+```bash
+$ mpirun -np 5 -hosts worker,localhost ./cpi
+#ホスト名の代わりにIPアドレスでも良いです。
+```
+
+予め用意したホストファイルを使うこともできます。
+
+```bash
+$ mpirun -np 5 --hostfile mpi_file ./cpi
+```
+
+これでmanagerが接続しているマシンでMPIプログラムが動くはずです!
+
+## 一般的なエラーやTIPS - Common errors and tips
+
+* 実行ファイルを実行しようとしているすべてのマシンで、MPIのバージョンが同じであることを確認してください。これを読んでいる時の推奨バージョンは [MPICH2](http://www.mpich.org/downloads/)を参照してください。
+* manager の `hosts` ファイルには、 `manager` とワーカーノードのローカルネットワーク IP アドレスを記述します。ワーカには`manager`と自分自身のエントリが含まれている必要があります。
+
+例を示します。managerには以下のようなhostsが必要になります。
+
+```bash
+$ cat /etc/hosts
+127.0.0.1 localhost
+#127.0.1.1 1944
+
+#MPI CLUSTER SETUP
+172.50.88.22 manager
+172.50.88.56 worker1
+172.50.88.34 worker2
+172.50.88.54 worker3
+172.50.88.60 worker4
+172.50.88.46 worker5
+```
+このとき、worker3に必要な最低限のhostsは以下の通りです。
+
+```bash
+$ cat /etc/hosts
+127.0.0.1 localhost
+#127.0.1.1 1947
+
+#MPI CLUSTER SETUP
+172.50.88.22 manager
+172.50.88.54 worker3
+```
+* MPIを使用してプロセスを並列実行しようとする場合、ローカルだけ、ローカルノードとリモートノードの組み合わせでプロセスを実行することができます。リモートのみでプロセスを起動することは**できません**。
+
+以下の呼び出しは正常です。
+```bash
+$ mpirun -np 10 --hosts manager ./cpi
+# To run the program only on the same manager node
+```
+
+以下の呼び出しは正常です。
+
+```bash
+$ mpirun -np 10 --hosts manager,worker1,worker2 ./cpi
+# To run the program on manager and worker nodes.
+```
+
+ですが次の呼び出しをmanagerから行うことはできません(worker1からなら良いのですが)。
+
+```bash
+$ mpirun -np 10 --hosts worker1 ./cpi
+# Trying to run the program only on remote worker
+```
+
+## 次は? - So, what's next?
+
+クラスタが構築できました!わくわくしますか?ついに並列実行できるプログラムを書くための詳細を知る時が来ました。[MPI hello world lesson]({{ site.baseurl }}/tutorials/mpi-hello-world/)から始めるのが良いです。もしも、Amazon EC2インスタンスを使って同じことを再現したいのであれば、[building and running your own cluster on Amazon EC2]({{ site.baseurl }}/tutorials/launching-an-amazon-ec2-mpi-cluster/)を見てください。その他のレッスンについては、[MPIチュートリアル]({{ site.baseurl }}/tutorials/)のページを参照してください。
+
+ローカルクラスタのセットアップで何か問題があれば、遠慮なく以下にコメントしてください。
\ No newline at end of file