データフローコンピュータとは

データフローコンピュータとは、データそのものが流れを指定することによって 計算が進んで行く計算機システムのことで、みなさんが普段利用している計算機 システム ( そう、君が今利用しているコンピュータも.. ) の動作原理である、 ノイマン型のコンピュータシステム と形式が異 なります。
このため、データフローコンピュータは、 非ノイマン型の計算機システム の一つ と呼ばれています。
しかし、今日(オープンキャンパスで) は、そのような難しいことは、さておいて、 実際に、触ってみて、直感的に楽しんでいただければと思います。

データフローコンピュータのエミュレータ

データフローコンピュータエミュレータ (Data Flow Computer Emulater : 略して DFCE, 決して CDEF ではない.. ) は、このデータフロー型の計算機の小さなエミュレータです。
もちろん、決して実用的なものとはいえず、他愛の無い物ですが、直感的 操作でき、データフロー型計算機の振る舞いを、なんとなく理解してもらえば と思って作ってみました。

DFCE を使ってみよう

DFCE の起動

このシステムは、java 言語で作成されていますので、次のように実行します。
java -jar dfce.jar
でも、これは面倒なので、
dfce
でも Okey です。

まずは、start ボタンを確認

DFCE が起動したら、まず、確認して欲しいのは、start ボタンです。左上の方 の上から二段目にいくつかのボタンが並んでいますが、その左から4番目が start ボタンです。
この start ボタンは、「計算を始めなさい」という意味で、今後、何度も 押すことになるので、ぜひ 覚えておいてください ( 最初は押しても何もおきません )。
逆に、間違って押すと、うっとうしいのが、同じ並びの一番右のボタンである reNew ボタンです。
これは、DFCE を最初の状態に戻してしまいます。プログラムを作成中に、間違って このボタンを押すと、せっかく入力したプログラムが消えてしまいますので、 注意してください。

プログラムフィールド

ボタンの並びの下の何も書いていない部分が、プログラムを書く場所です。 といっても、安心してください。別にプログラムを書くといっても、対した 作業ではありません。単に、マウスを使って、予め用意されている色々な図形 を置いたり、あるいは、その間に線を引いたりするというそれだけの作業です。
キーボードも利用しますが、本当に必要なのは、せいぜい、数字キーだけです ので、あまり気にする必要はありません。 とにかくやってみればすぐにでもわかります。

部品を置いてみよう

まず、プログラムフィールドの何もないところ ( といっても、最初は、どこにも 何もないですから、どこでもかまいません.. ) で、左クリック ( 右利きの 人は、マウスの左のボタン、普通は人指し指で押すボタンを、カチっと、押して すぐに離す行為。慣れなければ、何度もやってみよう.. ) をすると、そこに 部品メニューがでてきます。
部品メニューには、 7 つ項目があり、上から、input, output, binop, uniop, marge, branch, if となっています。これが、データフローコンピュータのプログラムを 作る基本部品となります。
以下では、この部品をプログラムフィールドに配置して行くことによって、 プログラムを作成してゆくわけです。
まちがって、この部品メニューが出てしまった人は、やはり、プログラムフィールドの 何もないところで、右クリック ( 同じく、右利きの人は、中指ボタンで、カチっと する ) と、部品メニュー消えますので、覚えておいてください。
メニューが出たら、次は、基本的に、その中の一つをクリックします。例えば、 プログラムフィールドの上の方で、部品メニューを出し、更に、メニューの 一番上の input をもう一度、右クリックしてください。すると、横長の四角 に囲まれた 1 という数字と、その四角の下に○と×が重なった図がでてきました。
これが、input 部品です。これは、後で述べるように、データを入力するための 部品です。
次に、プログラムフィールドの下の方で、今度は、output 部品をおいてみてください。 これは、--- が長四角で囲まれ、その上に、◎がついているものです。

部品を動かしてみよう

部品の位置が気に入らない場合は、その部品を動かすことができます。
部品を動かすには、まず、部品のできるだけ、真中当たり ( 文字のある部分が 真中に相当します ) で、左ボタンを押します ( 離してはいけません ) 。 そうすると、部品が赤くなります。 そしてその状態で、左ボタンを押したまま、マウスを動かすと、部品がそのマウスの動き に合わせて移動することがわかります。 このように、ボタンを押し、その状態で、マウスを移動した上で、ボタンを離すことを ドラッグと呼びます。部品を移動するには、部品をドラッグすればよいわけです。
望みの位置まで、部品が移動したら、その状態で、左ボタンを離せば、部品は その位置にとどまります。

部品を消してみよう

不要な部品を消すのは、簡単です、その部品の上で、右クリックします。そうすると その部品は消えます。

結線してみよう

今度は、目標が小さいので少し難しいのですが、結線をしてみたいと思います。
結線とは、部品同士を結びつける作業です。
まず、input 部品の下にある、×の付いた○ ( 以下、出力端子と呼びます ) で、 左ボタンを押します。そのまま、マウスを移動して、今度は、output 部品の上に ある◎ ( 以下、入力端子と呼びます )、まで、マウスを持って行きます。すると、 マウスの移動にそって、出力端子から、マウスの位置まで、赤い線が引かれます。
この線は、マウスの移動に従って、引きなおされることに注意してください。
そして、入力端子上で、マウスを放すと、その線が確定し、線は青くなります。
もし、ボタンを放したときに、線が消えてしまったら、それは、残念ながら 上手に、入力端子の上まで漏って行けなかったことを意味しますので、 もう一度、出力端子の上でボタンを押すところからやりなおしてください。

結線を消してみよう

間違って結線してしまった場合に備えて、結線の消し方をおしえておきましょう。 結線を消すのは、単に、その結線されている線の出力端子側を左クリックするだけ です。上手に結線できるまで、何度か、結線をしたり、消したりしてみましょう。

最初のプログラムを実行してみよう

さて、ここまで、きたら、プログラムフィールド上には、input 部品と、output 部品 が一つずつ置かれており、input 部品の出力端子から、output 部品の入力端子へ 結線がなされているはずです。
これが、最小 ( かつ、最初の.. ) プログラムです。ほら、簡単だったでしょう。
せっかくだから、実行してみましょう。これを実行するには、単に、最初に述べた start ボタンを左クリックするだけです。やってみてください。
すると、結線の上に○が現れ、それが、下まで行き、最後に、output 部品の "---" の部分が、1 に変わったと思います。実は、これだけです。
つまり、データフローコンピュータでは、この結線の上を移動する○がデータであり それが流れることが計算ということになります。

input 部品の内容を変えてみよう

今の、プログラムでは、input 部品にかかれていた 1 が、output 部品まで移動した わけです。 そこで、この input 部品の値の変え方を教えましょう。 やりかたは簡単です。単に、input 部品の真中当たりで、左クリックするだけです。 そうすると、値を入れるためのダイアログボックスが出てきます。 ここに、好きな数値をいれて、了解のボタンを押せば、その数値が、input 部品の 中に表示されると思います。 この状態で、start すれば、今度は、output 部品に入る数値も、input 部品の 値と同じになるこがわかると思います。

足し算のプログラム

次は、二つの数を入力し、その数を足した結果を求めることにします。
このために、プログラムフィールドを最初の状態にもどすために、reNew ボタンを おしましょう。 せっかく作成したプログラムですが、まあ、惜しくはないでしょう。
とりあえず、最初のプログラムと同様に、input 部品を、今度は、二つ上の方 に横に並べてください。位置は、適当でかまいません。output 部品は、下の方 の真中に一つです。
次に、真中の当たりで、今度は、binOp 部品を一つおいてください。 すると、今度は、大きな正方形で、入力端子 ( ◎ ) が左右に一つずつ、 そして、下に、出力端子 ( ×つき○ ) が付いた部品が現れます。 なお、この部品には、最初から add とついてますが、ご明察の通り、これは 足し算 ( addition ) を意味します。
二つの input 部品の出力端子から、binOp 部品の入力端子に結線を行い、 更に、binOp 部品の出力端子を、output 部品に入力端子に結線すれば、 プログラムは終わりです。
start ボタンを押して、二つの input 部品の中の数字を足した結果が、output 部品に 入ること確認してみてください。 input 部品の内容の数値を、色々変えて、実際に、足し算が行われていることを 確認してください。

その他の二項演算子

次に、今度は、引き算をしてみましょう。やり方は、見当が付くと思います。 つまり、足し算の場合と同じように、真中に引き算の部品を置けば済むわけです。
しかし、問題は、引き算の部品がどこにあるかということですね..。
実は、引き算は、足し算と同じ binOp が役割を果たします。上記の足し算の プログラムで、真中にある binOp 部品を左クリックしてみましょう。そうすると binOp 部品の役割を選択する機能メニューが表示されると思います。 その機能メニューで、下向きの▼をもう一度左クリックすると、現在の add の他に、sub ( subtract : 引き算 ) や、mul ( multiply : 掛け算 )、 div ( divide : 割り算 ) などが、出てきますので、それを選択 ( 該当する部分を左クリック ) すればよいわけです。
その他の機能に関しては、 機能表 を参照 してください。
ここでは、引き算ですので、sub を選択します。そして、了解すれば、 部品の上に書かれている表示が、add から、sub に変わったと思います。 これで、足し算のプログラムが引き算のプログラムに変わりました。試して みてください。
[演習] 他の演算子も試してみましょう。
このことから、解ったように binOp というのは、実は、 二項演算子 ( Binary Operator ) のことだったわけです。

uniOp も使ってみよう

聡い方は、すでに、binOp の説明から、uniOp の正体も、薄々と 感づいていらっしゃるかと思いますが、uniOp の正体は、 単項演算子 ( Uniary Operator ) です。つまり、一入力一出力 なわけで、いわゆる関数と呼ばれるものが全てこれです。
現在の DFCE では、それほどの機能がありませんが、いくつかの単項演算子 が利用可能で、これの使い方は、入力端子が一つという点を除けば、binOp と 全く利用法は同じです。
例えば、uniOp の minus を使って、入力された数値の負号を反転した結果を 出力するプログラムを考えてみましょう。
上に、input 部品、下に output 部品という基本はかわりません。真中に、 uniOp 部品を一つ作り更に、それを左クリックして、機能を minus に変えます。 後は、二本の結線をするだけです。
[演習] 入力した値を 2 増やすプログラムを考えなさい。ただし、input 部品は、 は一つしか利用してはいけません(ヒント:uniOp には、1 増やす部品がありますが、 これを二つ利用すれば..)。

流れを増やす分岐部品

次は、複数の計算を同時に行ってみましょう。例えば、二つの入力値の和と積を 同時に計算するプログラムを考えます。 もちろん、プログラムフィールド上に二つのプログラム ( 和の計算と、積の計算 ) を並べて実行するのもありですが、ポイントは、入力を二つ、出力を二つとしたい ということです ( 並べる方法だと、入力が四つ必要になります )。
そこで、利用するのが、一つの入力値を二つに分けるための部品 branch 部品です。
二つの input 部品を画面の上に二つ並べ、更に、その input 部品の下に、それぞれ 一つずつ、branch 部品を置くことにします。 そして、input 部品の出力を branch 部品の入力端子に結線すれば、branch 部品の 二つの出力端子からは、input 部品から入れられた値と同じ値が、二つに分かれて それぞれ出力されるわけです。 後は、それぞれ、binOp 部品の add と、binOp 部品の mul にそれぞれつないで、 その出力を、二つの output 部品につなぐだけです。
[演習] 四則 ( 和、差、積、商 ) を計算するプログラムを書いてみましょう。

ここでちょっと、パズル

ここまでに学んだ部品 ( まだ、学んでいない部品があるのですが、 それは置いておいて.. ) だけを使って、二つの数の大きな方 (実際は、小さくない方) を出力するプログラムを考えてみましょう。
まず、全体の構成ですが、上に input 部品が二つで、下に output 部品が一つ という構成は、動かないでしょう。二つの input 部品の値を比較し、その内の 大きい方が、下の output 部品に入るわけです。 次に、二つの数の大きい方ということですが、これは、binOp の中に gt という 機能がありますから、これが利用できそうです。 問題は、この結果をどう利用するかということになります。
で、ここで、いきなり、ヒントなのですが、次のヒントをみて答えがわかるでしょうか ちょっと考えてみてください。
  1. gt 部品の結果の出力は 1 (真) か 0 (偽) のどちらかになります。
  2. 任意の数に 0 を掛けると、 0 になります。
  3. 任意の数に 1 を掛けると、その数そのものになります。
  4. 任意の数に 0 を足すと、その数そのものになります。
ヒントといっても、なんだか当たり前のことばかりですね。しかし、これらの 性質を上手に使うと問題の解答が得られます。
もう一つ、ヒント。利用する部品は、後、branch 三つと、mul が二つ、 add が一つ、そして、uniOp の not が一つです。
[演習] わかった人は、実際にやってみてください。
さて、わかりましたか ? もし、解らなかったとしても、別に悲観すること はありません。 なぜならば、これは、かなりトリッキーなことをしているからです。
とりあえず、プログラムを作ってみましょう ( もし、以下の説明で 良くわからない場合は、周りの人に聞いてみると良いでしょう )。
  1. まず、前述の様に、上の方に、input 部品を二つ並べます。そして、その下に branch 部品をそれぞれ一つずつ置いてください。もちろん、input 部品の出力 と、それらの branch 部品の入力をそれぞれ結線します。
  2. 次に、二つの branch 部品の間に、binOp の gt 部品を置きます。そして、二つ の branch 部品の一つの出力を、その gt 部品の入力に結線します。 この結果、gt 部品の出力には、二つの入力に従って、 真 ( = 1 : 左の入力が大きい.. ) か、偽 ( = 0 : 左は大きくなかった ) が出力されます。
  3. 更に、その gt 部品の下に、三つ目の branch を置き、その出力を二つに分けます。
  4. 次に、左側に mul 部品を置きます。この add 部品には、左の input の内容 ( branch の残りの一つです ) と、gt の内容 ( gt の下の branch の左側 ) を入れます。 この結果、この mul 部品の出力に何が出るかお分かりでしょうか ? もし、左の input の方が大きい数値だったとしましょう。その場合、gt の出力は 真、すなわち 1 が出ます。これが、mul の一方の入力です。そして、もう一つの 入力は、左の input そのものですから、結果は、input そのものになります。 逆に、左の input の方が大きくなかったらどうでしょう。今度は、gt の出力が 偽、すなわち 0 が出ます。これが、mul の一方の入力ですから、出力は、当然 0 になるわけです。 なんとなく解ってきたでしょうか ?
  5. 次に、右側です。gt の下の branch の右側の近くに、唯一の uniOp 部品である not を置き、結線します。 そして、その下に更に、再び、mul 部品を置き、not の出力と、そして、右側 input の残りをそれぞれ、mul 部品に結線します。 この結線は、左と良く似ていますが、違いは、gt の出力に not がついていること です。not は、真偽 ( つまり、1 と 0 ) を反転しますから、結果は、以下のように なります。 つまり、左が大きかったら 0, そうでなければ、右側の input の値になります。
  6. ここまでの結果をちょっとまとめてみましょう。
    左右の区別 / 条件 左が大きかった 左が大きくなかった
    左の mul の出力 左の input の値 0
    右の mul の出力 0 右の input の値
    よろしいですか ?
  7. いよいよ仕上げに入ります。残っている部品は、binOp の add だけです。そして、 プログラムフィールドに、残っている出力端子が二つで、入力端子は一つ。何も 迷うことはありませんね。output 部品の上に add 部品を置き、残った端子を全て 結線します。後は実行するだけです。
ちょっと、難しかったですね..。えっ、「とっても難しかった」ですか ? いやぁ、実は、まだ説明していない部品があるせいで、こんなに変なこと になっているのです。 残った部品を学べば、同じ問題が、もっとわかりやすく実現できると思います。 これについては、もう一度、触れることにしましょう。
[演習] このプログラムに小さい方の数を出力するプログラムを考えなさい。

流れを一つにまとめる合流部品 ( marge )

ここから説明する部品は、ちょっと、解りにくいかもしれません。なぜ、解り にくいかといえば、それ単独で利用しても、あまり、意味がないからです。 つまり、他の部品と組み合わせたり、組み合わせる位置によって、この部品の 価値が変わるということです。特に、( marge ) は、それ自身なんてこともな い部品 ( 単に、二つの入力端子のどちらかに値が来るとその結果が、出力に そのまま流されるだけ.. ) なので、何に使うのか悩んでしまいそうな部品なの ですが、実をいえば、これがあるのとないのでは、天と地の差があるほど、 重要な部品であり、この部品ほど使いでのある部品もないと言えます。

無限カウンターを作ってみよう

とりあえず、次のプログラムを作成してみてください。
  1. 一番上に input 部品を置きます。
  2. その下に marge を置き、その入力端子を input の出力端子と結びます。
  3. その下に uniOp の inc を置き、marge の出力を、inc の入力に入れます。
  4. inc の下に branch を置き、inc の出力を、branch の入力に入れます。
  5. branch の下に output を置き、branch と結びます。
  6. 最後に残った、branch の出力を、marge の残った入力につなぎます。
さて、input には、最初に 1 が入っていますが、これを 0 に変えて、 start ボタンを押してください。 何がおきるでしょうか ? そうです。プログラムは止まらず、output には、 1, 2, 3, ... と無限に数値が増えて行く様子がわかると思います。
これが、無限カウンターであり、いわゆる、「繰り返し (loop) 構造」で、 これによって、「有限な記述で、無限の処理を可能にする」仕組み なわけです。
ところで、プログラムを止める方法ですが... これは、今まで使ったことが なかったかもしれませんが、stop ボタンを押すだけです。
[演習] 偶数の列を無限に出力するプログラムを作成しなさい。

有限回の繰り返しには ( if 部品 の利用 )

無限回を繰り返すというのは、それなりに面白いことではありますが、 もちろん、普通のプログラムでは、一定回数だけ繰り返して、お仕舞いに なるのが普通です。
そこで、繰り返しを止める方法を考えてみることにしましょう。
これに利用できるのが、if 部品です。if 部品は、左入力端子によって、 データの流れをせき止める機能があります。この性質を利用することによって、 無限繰り返し ( loop ) をせき止め、有限な繰り返しを作ることが可能になります。
では、与えられた数 ( input 部品による .. ) - 1 から、0 までの数を順 に count down するプログラムを考えてみましょう。
次のプログラムを入力してみてください。
  1. まずは、前述の 無限 count と同じものを作ります。
  2. 次に、inc を dec に変えます。
  3.  
  4. marge の下に、branch を置き、marge の出力を branch に入れます。
  5. branch の下に if 部品の true を置きます。
  6. branch の出力を両方とも if 部品の二つの入力端子に入れます。
  7. true の出力を dec 部品の入力に入れれば、改造は終了です。
ここでもちょっとしたトリックが利用されていますが、お分かりでしょうか ? いずれにせよ、これによって、input 部品の数 - 1 から 0 まの数値が、順に output 部品に入ります。
[演習] このプログラムを変更して、input 部品の数から 1 までの数値が 順に出力されるようにしなさい。

marge と if 部品のもう一つの利用法

branch, if と marge 部品は、何時でも、いっしょに利用されると考えて良い と思います。なぜなら、branch が流れを増やし、if 部品が、不要な流れを せき止め、最後に、marge が、それをまとめるという形に使えるからです。 例の、大きい方の数を出力するパズルを再考してみましょう。実は、あの プログラム中の mul は、if に相当し、add は、marge に相当しているという ことが、解るのではないかとお思います。
[演習] 今度は、大きな数を出すプログラムを、if, marge を使って、書き直し てみなさい。作業としては、mul を、true に、add を marge にするだけです。
[演習] not と true の組み合わせを false にしてみなさい。これが典型的な 条件分岐の形です。

終わりに

以上で、DFCE に関する全ての部品に関する説明を終わりました。 どうです、それほど、難しくはなかったのではないかと思います ( 途中のパズルを除いてですが.. )。
DFCE には、実は、まだ、重要な欠点があります。それは、単に、プログラムフィールドが小さいということだけでなく、作成したプログラムを更に、名前をつけて、 組み合わせるためのマクロ機能がないということです。
将来は、この機能も追加し、更に、整数だけでなく、実数値や、文字列などが 利用できるようなシミュレータを作ってみたいと思っています。