はじめに
本記事シリーズは母国語のプログラミング言語が存在するという文化的価値をアピールするためのもので、プログラミング一般の入門を意図するものではありません。とはいっても題材としては定番アルゴリズムのいくつかを疑似言語ではなくコンパイル・実行可能なプログラミング言語の日本語で書いてみようというたてつけとなります。
Mind(マインド)
プログラミング言語Mind(マインド)は自然な日本語で記述できるスタック指向の軽量中間コードコンパイラ言語です。ただし単語間の分かち書きが必須であくまで形式言語です。逆ポーランド記法1の範囲で分かち書きされた日本語単語の語順が自然と日本語の語順となるという意味の「自然さ」で書くことができ、独自の軽量中間コードのランタイム実行で非常に高速です。実装言語はCまたはMind。初版の登場は1985年で2025年は生誕40周年となりました。
Mind(マインド)の入手方法
無償版のMind version 8 (windows版linux版)を下記の公式サイトからダウンロードできます。フリーメールでかまいませんのでメールアドレスをご登録くださいませ。
定番アルゴリズム:ベルマン‐フォード法とは
アルゴリズムは、問題を解決するための手順や計算方法を意味します。アルゴリズムにはいくつかの定番ロジックが存在します。
ここではその中のひとつ「ベルマン‐フォード法」を扱ってみます。「ベルマン‐フォード法」はある頂点から他のすべての頂点への最短距離と経路を求めるためのロジックです。
同様の定番アルゴリズムに「ダイクストラ法」がありますが、頂点間(辺)のコスト:重み≒距離が負数でなければ優先度付きキューを使ったダイクストラ法のが速いのですが、負数がある場合は「ベルマン‐フォード法」が使われるのが一般的です。
優先度付きキューを使ったダイクストラ法についてはこちらの記事を参照してください。
お題のソースコード
今回は下記のような経路を想定します。数字は頂点の番号で4つの頂点があるとします。かっこ値は頂点間の距離(コスト:重み)を意味します。
コスト:重みはおおむね距離(単位:長さ)と考えて問題はありませんが、マイナスのコストを考慮する場合は、その他の属性ウエイト:重みを加味したなんらかの総合値と考えた方がよい場合があります。(距離に近い属性であれば方向とか)
1 -------(5)------> 3
| > |
| / (3)
(4) / |
| (-2) |
| / v
+------> 2 4
^ |
| |
+----(-6)--+
上記のグラフの頂点間の関係を分割すると下記のようになります。
1 → 2 (4)
1 → 3 (5)
2 → 3 (-2)
3 → 4 (3)
4 → 2 (-6)
Mindの配列の添え字の基数は1から始まりますので、下記のような構造体の1次元配列で上記の経路を記述します。
エッジ[1] = new Edge(1, 2, 4);
エッジ[2] = new Edge(1, 3, 5);
エッジ[3] = new Edge(2, 3, -2);
エッジ[4] = new Edge(3, 4, 3);
エッジ[5] = new Edge(4, 2, -6); // 2→3→4→2 の負閉路
また、上記の疑似言語表現では一般的なプログラミング言語の配列表現でかぎカッコを使っていますが、Mindの場合はかっこ()表記となります。また、右辺は一般的なオブジェクト指向言語での構造体の初期化処理を表現していますが、Mindの場合は異なる表記となります。
辺数最大は 定数 5辺。
グラフは 構造体
始点は 変数
終点は 変数
コストは 変数
エッジは 始点と 終点と コスト
全体は 辺数最大の エッジ。
Mindの場合、構造体の1次元配列は容易に定義できます。(引用時は基底の変数名またはそれをグループ化した中間変数名と中かっこでインデックスを表現します。)
グラフを初期化とは (・ → ・) 本定義
1と 2と 4を エッジ型に変換し エッジ(1)に 入れ
1と 3と 5を エッジ型に変換し エッジ(2)に 入れ
2と 3と -2を エッジ型に変換し エッジ(3)に 入れ
3と 4と 3を エッジ型に変換し エッジ(4)に 入れ
4と 2と -6を エッジ型に変換し エッジ(5)に 入れ
※~略~
前記の構造体1次元配列の初期化処理の疑似言語表現はMindの場合、上記のようなイメージとなります。「エッジ型に変換」はソースコード全文内の定義を参照してください。
∞は 定数 1000000000。 (10億)
∞は経路の距離に対して十分大きな無限大と言える値です。今回も10億としています。
下記がソースコード全文となります。仮定義を使ってメインが冒頭に来るようにして、各処理の実装はその後で定義してみました。
∞は 定数 1000000000。 (10億)
頂点数最大は 定数 4頂点。
辺数最大は 定数 5辺。
グラフは 構造体
始点は 変数
終点は 変数
コストは 変数
エッジは 始点と 終点と コスト
全体は 辺数最大の エッジ。
エッジ型は 型紙
始点_は 変数
終点_は 変数
コスト_は 変数
全体は 始点_と 終点_と コスト_。
頂点間距離は 頂点数最大の 変数。
エッジ型に変換するとは (始点、終点、コスト → エッジ型) 仮定義。
エッジ型を表示するとは (エッジ型 → ・) 仮定義。
グラフを初期化とは (・ → ・) 仮定義。
ベルマン‐フォード法で最短経路を求めるとは (・ → ・) 仮定義。
負閉路を検出するとは (・ → ・) 仮定義。
結果を表示するとは (・ → ・) 仮定義。
メインとは (・ → ・)
グラフを初期化し
ベルマン‐フォード法で最短経路を求め
結果を表示する。
グラフを初期化とは (・ → ・) 本定義
※ --- グラフ定義(例) ---
※ 1 → 2 (4)
※ 1 → 3 (5)
※ 2 → 3 (-2)
※ 3 → 4 (3)
※ 4 → 2 (-6) ← 負閉路を作る例
1と 2と 4を エッジ型に変換し エッジ(1)に 入れ
1と 3と 5を エッジ型に変換し エッジ(2)に 入れ
2と 3と -2を エッジ型に変換し エッジ(3)に 入れ
3と 4と 3を エッジ型に変換し エッジ(4)に 入れ
4と 2と -6を エッジ型に変換し エッジ(5)に 入れ
※初期化状態の確認
「グラフの初期化状態を表示する」を 一行表示し
辺数最大で 回数指定し
回数を 数値表示し 「 」を 表示し
エッジ(回数)で エッジ型を表示する
繰り返すこと。
エッジ型に変換するとは (始点、終点、コスト → エッジ型) 本定義
エッジ型変数は 構造体 エッジ型
始点Lは 変数
終点Lは 変数
コストLは 変数
コストLに 入れ
終点Lに 入れ
始点Lに 入れ
エッジ型変数の 始点_に 始点Lを 入れ
エッジ型変数の 終点_に 終点Lを 入れ
エッジ型変数の コスト_に コストLを 入れ
エッジ型変数を 返すこと。
エッジ型を表示するとは (エッジ型 → ・) 本定義
親のエッジは 構造体情報
親のエッジに 入れ
親のエッジの 始点_を 数値表示し 「→」を 表示し
親のエッジの 終点_を 数値表示し 「 (」を 表示し
親のエッジの コスト_を 数値表示し 「)」を 一行表示すること。
ベルマン‐フォード法で最短経路を求めるとは (・ → ・) 本定義
頂点Noは 変数
辺Noは 変数
更新済は 変数
始点Lは 変数
終点Lは 変数
コストLは 変数
頂点数最大で 回数指定し
頂点間距離(回数)に ∞を 入れ
繰り返す
頂点間距離(1)を クリアし ※0を 入れ
頂点Noに 1を 入れ
頂点数最大で 回数指定し
更新済を クリアし
辺Noに 1を 入れ
辺数最大で 回数指定し
始点Lに 始点(辺No)を 入れ
終点Lに 終点(辺No)を 入れ
コストLに コスト(辺No)を 入れ
頂点間距離(始点L)が ∞と 異なる
かつ 頂点間距離(終点L)が 頂点間距離(始点L)に コストLを 加えたより 大きい
ならば
頂点間距離(始点L)と コストLを 加えて 頂点間距離(終点L)に 入れ
更新済を セットし
つぎに
辺Noを 一つ増加し
繰り返す
更新済が 偽? ならば 打ち切り つぎに
頂点Noを 一つ増加し
繰り返すこと。
結果を表示するとは (・ → ・) 本定義
「頂点No1からの各頂点の最短距離結果」を 一行表示し
頂点数最大で 回数指定し
「頂点No:」を 表示し 回数を 数値表示し
「 距離:」を 表示し 頂点間距離(回数)を 数値表示し 改行し
繰り返す
負閉路を検出した
ならば
「負回路を検出しました。」を 一行表示し
つぎに。
負閉路を検出するとは (・ → 真偽) 本定義
検出済は 変数
始点Lは 変数
終点Lは 変数
コストLは 変数
検出済を クリアし
辺数最大で 回数指定し
始点Lに 始点(回数)を 入れ
終点Lに 終点(回数)を 入れ
コストLに コスト(回数)を 入れ
頂点間距離(始点L)が ∞と 異なる
かつ 頂点間距離(終点L)が 頂点間距離(始点L)に コストLを 加えたより 大きい
ならば
検出済を セットし
打ち切り
つぎに
繰り返す
検出済を 返すこと。
お題のソースコードをコンパイル
では、コンパイルしてみます。Mind8によるコンパイル結果です。
C:\developments\vscode\mind9\algorithm>mind bellmanford file
日本語プログラミング言語 Mind Version 8.07 for Windows
Copyright(C) 1985 Scripts Lab. Inc.
コンパイル中 .. 終了
Coping.. c:\pmind\bin\mindex.exe --> bellmanford.exe
実行結果
実行結果です。
C:\developments\vscode\mind9\algorithm>bellmanford
グラフの初期化状態を表示する
1 1→2 (4)
2 1→3 (5)
3 2→3 (-2)
4 3→4 (3)
5 4→2 (-6)
頂点No1からの各頂点の最短距離結果
頂点No:1 距離:0
頂点No:2 距離:-16
頂点No:3 距離:-13
頂点No:4 距離:-10
負回路を検出しました。
かなり芸のない出力ですが、今回は負閉路が存在するため各頂点同士の距離はマイナスで算出されました![]()
ぱっと見た感じ、違和感のある結果ですが、ベルマン‐フォード法のロジックでは更新済がセットされてしまうため、緩和が最大回数反復されたためです。なにかの機会に負閉路なしのグラフでも実行してみようと思います。
おわりに
いかがでしたでしょうか?わたしはわが国に母語によるプログラミング言語が存在することを誇りに思っております。言語は文化。こんにちの日本語のポップスやアニメソングなどが海外でそのまま歌われるような近況を鑑みますと、純然たる技術基盤として超強力な米欧発プログラミング言語勢と存在意義を争うこともなく、日本語の文化として海外でも日本語プログラミング言語の愛される日が来るのやもしれません。
-
演算子を被演算子の中間に記述する中置記法 1 + 2、前に記述する前置記法(ポーランド記法)+ 1 2、後に記述する後置記法(逆ポーランド記法)1 2 +がある。日本語は1と 2を 足す。 ↩