グラフ理論 では、 および の グラフ の 最小 全域木 (MST)は 、 のすべての頂点を含み、最小の重みを持つ
の 木 サブグラフ です。
T
{\displaystyle T}
G
=
(
V
、
E
)
{\displaystyle G=(V,E)}
|
V
|
=
n
{\displaystyle |V|=n}
|
E
|
=
メートル
{\displaystyle |E|=m}
G
{\displaystyle G}
MSTは、実用的かつ理論的な幅広い分野で活用されている、有用で多用途なツールです。例えば、ある企業が単一の倉庫から複数の店舗に特定の商品を供給したい場合、倉庫を起点とするMSTを用いて、各店舗への最短経路を計算することができます。この場合、店舗と倉庫は頂点として、それらを結ぶ道路は辺として表されます。各辺には、対応する道路の長さがラベル付けされます。
が 辺重みなし の場合 、すべての全域木は同じ数の辺を持ち、したがって同じ重みを持ちます。 辺重み付き の場合、 のすべての全域木の中で、 の辺の重みの合計が最小となる全域木は、 最小全域木 (MST)と呼ばれます。これは必ずしも一意ではありません。より一般的には、必ずしも 連結され ていないグラフには、 連結成分 ごとにMSTの 和集合 からなる最小全域 木 (minimum spanning forests)が存在します 。
G
{\displaystyle G}
G
{\displaystyle G}
MSTの発見はグラフ理論において広く普及している問題であるため、 これを解くための 逐次アルゴリズムが数多く存在します。その中には、 Prim 、 Kruskal 、 Borůvkaの アルゴリズムがあり、それぞれMSTの異なる特性を利用しています。これらはすべて同様の動作をします。 つまり、有効なMSTが発見されるまで、 のサブセットを反復的に拡張していくのです。しかし、実際の問題はしばしば非常に大規模であるため(道路網には数十億もの辺が存在することもあります)、 パフォーマンスが 重要な要素となります。パフォーマンスを向上させる一つの方法は、既知の MSTアルゴリズムを 並列化する ことです 。 [1]
E
{\displaystyle E}
プリムのアルゴリズム
このアルゴリズムはMSTの カット特性 を利用します。以下に、シンプルな高水準 擬似コード 実装を示します。
T
←
∅
{\displaystyle T\gets\emptyset }
S
←
{
s
}
{\displaystyle S\gets \{s\}}
繰り返し 回数 のランダム頂点は どこにあるか
s
{\displaystyle s}
V
{\displaystyle V}
|
V
|
−
1
{\displaystyle |V|-1}
最も明るいエッジ stを見つけ て T
を返す
(
あなた
、
v
)
{\displaystyle (u,v)}
あなた
∈
S
{\displaystyle u\in S}
v
∈
(
V
∖
S
)
{\displaystyle v\in (V\setminus S)}
S
←
S
∪
{
v
}
{\displaystyle S\gets S\cup \{v\}}
T
←
T
∪
{
(
あなた
、
v
)
}
{\displaystyle T\gets T\cup \{(u,v)\}}
各辺は正確に2回、つまり各端点を調べる際に観測されます。各頂点は、 ループの各反復における最軽量辺の選択を除いて、合計 回の操作で正確に1回検査されます。この選択は、多くの場合、 優先キュー (PQ)を用いて行われます。各辺に対して、最大1回の decreaseKey 操作( で 償却 )が実行され、各ループの反復で1回の deleteMin 操作( )が実行されます。したがって、 フィボナッチヒープ を使用すると、Prim アルゴリズムの合計実行時間は 漸近的 に になります 。
お
(
n
+
メートル
)
{\displaystyle O(n+m)}
お
(
1
)
{\displaystyle O(1)}
お
(
ログ
n
)
{\displaystyle O(\log n)}
お
(
メートル
+
n
ログ
n
)
{\displaystyle O(m+n\log n)}
ループは本質的に逐次的であり、適切に並列化できないことに注意することが重要です。これは、 に端点を持ち に を持つ最軽量の辺が、 へ の辺の追加によって変化する可能性があるため です。したがって、最軽量の辺を同時に2つ選択することはできません。しかしながら、 を 並列化する 試みはいくつか存在します。
S
{\displaystyle S}
V
∖
S
{\displaystyle V\setminus S}
T
{\displaystyle T}
1つのアイデアとしては、 EREW-PRAM マシン上で PQアクセスをサポートするためにプロセッサを使用し 、 [2] 合計実行時間を に短縮することが挙げられます 。
お
(
n
)
{\displaystyle O(n)}
お
(
1
)
{\displaystyle O(1)}
お
(
n
+
メートル
)
{\displaystyle O(n+m)}
クラスカルのアルゴリズム
クラスカルのMSTアルゴリズムは、 MSTの 循環性 を利用します。以下に高レベルの擬似コード表現を示します。
T
←
{\displaystyle T\gets }
各頂点が自身のサブツリーにあるフォレスト。
重み の昇順で
foreachを実行し 、 異なるサブツリーで T
を返す。
(
あなた
、
v
)
∈
E
{\displaystyle (u,v)\in E}
あなた
{\displaystyle u}
v
{\displaystyle v}
T
{\displaystyle T}
T
←
T
∪
{
(
あなた
、
v
)
}
{\displaystyle T\gets T\cup \{(u,v)\}}
のサブツリーは union-find データ構造に格納される ため、2つの頂点が同じサブツリー内にあるかどうかの確認は、amortised で可能です。 ここで、は 逆 アッカーマン関数 です。したがって、アルゴリズムの合計実行時間は です 。ここで、 は単値逆アッカーマン関数を表します。この関数に対しては、任意の現実的な入力が5未満の整数を生成します。
T
{\displaystyle T}
お
(
α
(
メートル
、
n
)
)
{\displaystyle O(\alpha (m,n))}
α
(
メートル
、
n
)
{\displaystyle \alpha (m,n)}
お
(
s
o
r
t
(
n
)
+
α
(
n
)
)
{\displaystyle O(sort(n)+\alpha (n))}
α
(
n
)
{\displaystyle \alpha (n)}
アプローチ1:ソートステップの並列化
プリムのアルゴリズムと同様に、クラスカルのアプローチにも、その古典的な変種では並列化できない要素があります。例えば、2つの頂点が同じサブツリー内にあるかどうかを判定する処理は、2つの和集合演算が同時に同じサブツリーを結合しようとする可能性があるため、並列化が困難です。実際に並列化が可能なのはソート処理のみです。 ソートは プロセッサ上で最適な場合、線形であるため 、全体の実行時間は まで短縮できます 。
お
(
ログ
n
)
{\displaystyle O(\log n)}
お
(
メートル
α
(
n
)
)
{\displaystyle O(m\alpha (n))}
アプローチ2:フィルター・クラスカル
もう一つのアプローチは、元のアルゴリズムを より積極的に成長させることです。このアイデアはOsipovらによって提唱されました。 [3] [4] Filter-Kruskalの基本的な考え方は、 クイックソート と同様に辺を分割し 、同じ木に属する頂点を結ぶ辺を除外することでソートコストを削減することです。以下に高レベルの擬似コード表現を示します。
T
{\displaystyle T}
filterKruskal( ):
KruskalThreshold の場合 :
kruskal( ) を返す
G
{\displaystyle G}
メートル
<
{\displaystyle m<}
G
{\displaystyle G}
pivot = chooseRandom( )
, partition( , pivot)
filterKruskal( )
filter( )
filterKruskal( )
return
E
{\displaystyle E}
(
E
≤
{\displaystyle (E_{\leq }}
E
>
)
←
{\displaystyle E_{>})\gets }
E
{\displaystyle E}
あ
←
{\displaystyle A\gets }
E
≤
{\displaystyle E_{\leq}}
E
>
←
{\displaystyle E_{>}\gets }
E
>
{\displaystyle E_{>}}
あ
←
あ
{\displaystyle A\gets A}
∪
{\displaystyle \cup }
E
>
{\displaystyle E_{>}}
A
{\displaystyle A}
パーティション( , ピボット):
foreach :
if weight( ) ピボット:
else return ( , )
E
{\displaystyle E}
E
≤
←
∅
{\displaystyle E_{\leq }\gets \emptyset }
E
>
←
∅
{\displaystyle E_{>}\gets \emptyset }
(
u
,
v
)
∈
E
{\displaystyle (u,v)\in E}
u
,
v
{\displaystyle u,v}
≤
{\displaystyle \leq }
E
≤
←
E
≤
∪
(
u
,
v
)
{\displaystyle E_{\leq }\gets E_{\leq }\cup {(u,v)}}
E
>
←
E
>
∪
(
u
,
v
)
{\displaystyle E_{>}\gets E_{>}\cup {(u,v)}}
E
≤
{\displaystyle E_{\leq }}
E
>
{\displaystyle E_{>}}
filter( ):
foreach :
if find-set(u) find-set(v):
return
E
{\displaystyle E}
E
f
i
l
t
e
r
e
d
←
∅
{\displaystyle E_{filtered}\gets \emptyset }
(
u
,
v
)
∈
E
{\displaystyle (u,v)\in E}
≠
{\displaystyle \neq }
E
f
i
l
t
e
r
e
d
←
E
f
i
l
t
e
r
e
d
∪
(
u
,
v
)
{\displaystyle E_{filtered}\gets E_{filtered}\cup {(u,v)}}
E
f
i
l
t
e
r
e
d
{\displaystyle E_{filtered}}
Filter-Kruskal は、ソート、パーティショニング、フィルタリングにおいて、エッジがコア間で単純に分割される直感的に簡単な並列化を備えているため、並列化に適しています。
ボルフカのアルゴリズム
Borůvka アルゴリズムの根底にある考え方は、 辺の縮約 です。辺は、 まず グラフから を削除し、次にすべての辺 を にリダイレクトすることで縮約されます 。これらの新しい辺は、以前の辺の重みを保持します。MST の重みだけでなく、それがどの辺で構成されているかを決定することが目的である場合、どの頂点ペア間で辺が縮約されたかを記録する必要があります。以下に、高レベルの擬似コード表現を示します。
{
u
,
v
}
{\displaystyle \{u,v\}}
v
{\displaystyle v}
{
w
,
v
}
∈
E
{\displaystyle \{w,v\}\in E}
{
w
,
u
}
{\displaystyle \{w,u\}}
T
←
∅
{\displaystyle T\gets \emptyset }
契約 の 戻り T
の 最も 軽い もの
|
V
|
>
1
{\displaystyle |V|>1}
S
←
∅
{\displaystyle S\gets \emptyset }
v
∈
V
{\displaystyle v\in V}
S
←
S
{\displaystyle S\gets S}
∪
{\displaystyle \cup }
{
u
,
v
}
∈
E
{\displaystyle \{u,v\}\in E}
{
u
,
v
}
∈
S
{\displaystyle \{u,v\}\in S}
{
u
,
v
}
{\displaystyle \{u,v\}}
T
←
T
∪
S
{\displaystyle T\gets T\cup S}
縮約によって、頂点ペア間に複数の辺が生じる可能性があります。最も軽い辺を選択するという直感的な方法は、 では不可能です 。しかし、頂点を共有するすべての縮約を並列に実行すれば、これは可能です。再帰は頂点が1つだけになった時点で停止します。つまり、アルゴリズムは最大で 回反復する必要があり、合計実行時間は で済みます 。
O
(
m
)
{\displaystyle O(m)}
log
n
{\displaystyle \log n}
O
(
m
log
n
)
{\displaystyle O(m\log n)}
並列化
このアルゴリズムの並列化の一つの可能性 [5] [6] [7]は、 多重対数的な 時間計算量、すなわち となり 、定数 が存在する という結果に なる 。ここで は、プロセッサ数台 を持つマシン上で 、辺と 頂点 を 持つグラフの実行時間を表す 。基本的な考え方は以下の通りである。
T
(
m
,
n
,
p
)
⋅
p
∈
O
(
m
log
n
)
{\displaystyle T(m,n,p)\cdot p\in O(m\log n)}
c
{\displaystyle c}
T
(
m
,
n
,
p
)
∈
O
(
log
c
m
)
{\displaystyle T(m,n,p)\in O(\log ^{c}m)}
T
(
m
,
n
,
p
)
{\displaystyle T(m,n,p)}
m
{\displaystyle m}
n
{\displaystyle n}
p
{\displaystyle p}
最も軽い接続辺を見つける // 対応
するサブグラフを各頂点に割り当てる //
各サブグラフを縮小する //
|
V
|
>
1
{\displaystyle |V|>1}
O
(
m
p
+
log
n
+
log
p
)
{\displaystyle O({\frac {m}{p}}+\log n+\log p)}
O
(
n
p
+
log
n
)
{\displaystyle O({\frac {n}{p}}+\log n)}
O
(
m
p
+
log
n
)
{\displaystyle O({\frac {m}{p}}+\log n)}
MST は、見つかった最も明るいエッジすべてから構成されます。
この並列化では、 の隣接配列グラフ表現を利用します 。これは、 頂点の 長さ、 各辺の端点の 長さ 、そして辺の重みの 長さの3つの配列で構成されます 。頂点 について、に 接続する各辺のもう一方の端点は、 と の間のエントリで見つけることができます。 の 番目の辺 の重み は にあります 。そして、の 番目 の辺が頂点 と の間にある 場合、かつ の場合に 限ります 。
G
=
(
V
,
E
)
{\displaystyle G=(V,E)}
Γ
{\displaystyle \Gamma }
n
+
1
{\displaystyle n+1}
γ
{\displaystyle \gamma }
m
{\displaystyle m}
m
{\displaystyle m}
c
{\displaystyle c}
m
{\displaystyle m}
i
{\displaystyle i}
i
{\displaystyle i}
γ
[
Γ
[
i
−
1
]
]
{\displaystyle \gamma [\Gamma [i-1]]}
γ
[
Γ
[
i
]
]
{\displaystyle \gamma [\Gamma [i]]}
i
{\displaystyle i}
Γ
{\displaystyle \Gamma }
c
[
i
]
{\displaystyle c[i]}
i
{\displaystyle i}
γ
{\displaystyle \gamma }
u
{\displaystyle u}
v
{\displaystyle v}
Γ
[
u
]
≤
i
<
Γ
[
u
+
1
]
{\displaystyle \Gamma [u]\leq i<\Gamma [u+1]}
γ
[
i
]
=
v
{\displaystyle \gamma [i]=v}
最も明るい入射エッジを見つける
まず、辺は各 プロセッサに分配されます。-番目のプロセッサは、 と の間に格納されている辺を受け取ります 。さらに、各プロセッサは、これらの辺がどの頂点に属しているかを知る必要があり( は辺の端点の1つしか格納していないため)、これを配列 に格納します。この情報は 、二分探索または 線形 探索 を用いて 取得できます 。実際には、後者のアプローチの方が漸近的には劣るものの、より高速な場合があります。
p
{\displaystyle p}
i
{\displaystyle i}
γ
[
i
m
p
]
{\displaystyle \gamma [{\frac {im}{p}}]}
γ
[
(
i
+
1
)
m
p
−
1
]
{\displaystyle \gamma [{\frac {(i+1)m}{p}}-1]}
γ
{\displaystyle \gamma }
p
r
e
d
{\displaystyle pred}
O
(
log
n
)
{\displaystyle O(\log n)}
p
{\displaystyle p}
O
(
n
p
+
p
)
{\displaystyle O({\frac {n}{p}}+p)}
ここで、各プロセッサは、それぞれの頂点に接する最も明るいエッジを決定します。
v
←
{\displaystyle v\gets }
find( , )
の場合、 if の 場合
i
m
p
{\displaystyle {\frac {im}{p}}}
Γ
{\displaystyle \Gamma }
e
←
i
m
p
;
e
<
(
i
+
1
)
m
p
−
1
;
e
+
+
{\displaystyle e\gets {\frac {im}{p}};e<{\frac {(i+1)m}{p}}-1;e++}
Γ
[
v
+
1
]
=
e
{\displaystyle \Gamma [v+1]=e}
v
+
+
{\displaystyle v++}
c
[
e
]
<
c
[
p
r
e
d
[
v
]
]
{\displaystyle c[e]<c[pred[v]]}
p
r
e
d
[
v
]
←
e
{\displaystyle pred[v]\gets e}
ここで問題となるのは、一部の頂点が複数のプロセッサで処理されることです。この問題の解決策として、各プロセッサが独自の 配列を持ち、後で縮約法を用いて他のプロセッサの配列と結合するという方法があります。各プロセッサは最大2つの頂点を持ち、それらは他のプロセッサでも処理され、各縮約は 単位 です 。したがって、このステップの合計実行時間は 単位 です 。
p
r
e
v
{\displaystyle prev}
O
(
log
p
)
{\displaystyle O(\log p)}
O
(
m
p
+
log
n
+
log
p
)
{\displaystyle O({\frac {m}{p}}+\log n+\log p)}
頂点へのサブグラフの割り当て
前のステップで収集された辺のみで構成されるグラフを観察してください。これらの辺は、最も軽い入射辺である頂点から遠ざかるように向いています。結果として得られるグラフは、複数の弱連結成分に分解されます。このステップの目的は、各頂点に、それが属する成分を割り当てることです。すべての頂点にはちょうど1つの出力辺があるため、各成分は擬似木、つまり成分内の最も軽い辺と平行に、かつ反対方向に走る1つの追加辺を持つ木であることに注意してください。次のコードは、この追加辺をループに変換します。
並列forAllの 場合
v
∈
V
{\displaystyle v\in V}
w
←
p
r
e
d
[
v
]
{\displaystyle w\gets pred[v]}
p
r
e
d
[
w
]
=
v
∧
v
<
w
{\displaystyle pred[w]=v\land v<w}
p
r
e
d
[
v
]
←
v
{\displaystyle pred[v]\gets v}
これで、すべての 弱連結成分は、根に ループ を持つ有向木になります 。この根が各成分の代表として選択されます。次のコードは、倍加法を用いて各頂点に代表を割り当てています。
forAllの 場合
∃
v
∈
V
:
p
r
e
d
[
v
]
≠
p
r
e
d
[
p
r
e
d
[
v
]
]
{\displaystyle \exists v\in V:pred[v]\neq pred[pred[v]]}
v
∈
V
{\displaystyle v\in V}
p
r
e
d
[
v
]
←
p
r
e
d
[
p
r
e
d
[
v
]
]
{\displaystyle pred[v]\gets pred[pred[v]]}
これで、すべてのサブグラフが スターに なりました。高度な技術を使うと、このステップには 時間がかかります。
O
(
n
p
+
log
n
)
{\displaystyle O({\frac {n}{p}}+\log n)}
サブグラフの縮小
このステップでは、各サブグラフが 1 つの頂点に縮小されます。
k
←
{\displaystyle k\gets }
部分グラフの数、
一対一関数の スタールートを見つける
V
′
←
{
0
,
…
,
k
−
1
}
{\displaystyle V'\gets \{0,\dots ,k-1\}}
f
:
{\displaystyle f:}
→
{
0
,
…
,
k
−
1
}
{\displaystyle \rightarrow \{0,\dots ,k-1\}}
E
′
←
{
(
f
(
p
r
e
d
[
v
]
)
,
f
(
p
r
e
d
[
w
]
)
,
c
,
e
o
l
d
)
:
(
v
,
w
)
∈
E
∧
p
r
e
d
[
v
]
≠
p
r
e
d
[
w
]
}
{\displaystyle E'\gets \{(f(pred[v]),f(pred[w]),c,e_{old}):(v,w)\in E\land pred[v]\neq pred[w]\}}
全単射関数 を求めるには、接頭辞和 を使用します 。頂点と辺の新しい集合ができたので、隣接配列を再構築する必要があります。これは、Integersort を in time で使用することで実行できます。
O
(
n
p
+
log
p
)
{\displaystyle O({\frac {n}{p}}+\log p)}
E
′
{\displaystyle E'}
O
(
m
p
+
log
p
)
{\displaystyle O({\frac {m}{p}}+\log p)}
複雑
各反復には 時間がかかり、逐次的な場合と同様 に反復が繰り返されるため、合計実行時間は になります 。 アルゴリズムの効率が の場合 、相対的に効率的です。 の場合、絶対的に効率的です。
O
(
m
p
+
log
n
)
{\displaystyle O({\frac {m}{p}}+\log n)}
log
n
{\displaystyle \log n}
O
(
log
n
(
m
p
+
log
n
)
)
{\displaystyle O(\log n({\frac {m}{p}}+\log n))}
m
∈
Ω
(
p
log
2
p
)
{\displaystyle m\in \Omega (p\log ^{2}p)}
Θ
(
1
)
{\displaystyle \Theta (1)}
m
∈
O
(
n
)
{\displaystyle m\in O(n)}
さらなるアルゴリズム
MSTを求める問題を扱う並列アルゴリズムは他にも複数存在します。プロセッサ数が線形であれば、この処理は [8] [9] で実現可能です。Bader とCongは、8コアで最適な逐次アルゴリズムよりも5倍高速なMSTアルゴリズムを発表しました。 [10]
O
(
log
n
)
{\displaystyle O(\log n)}
もう一つの課題は外部メモリモデルです。Dementievらが提案したアルゴリズムは、内部メモリのみを使用するアルゴリズムに比べて2~5倍しか遅くないと言われています [11]
参考文献
^ サンダース;ディーツフェルビンガー。マーティン;メルホルン。カート。ピーター (2014-06-10)。 アルゴリズムとデータ構造、Grundwerkzeuge 。スプリンガービューeg。 ISBN 978-3-642-05472-3 。
^ ブローダル、ガース・ストルティング;トラフ、ジェスパー・ラーソン。 Zaroliagis、Christos D. (1998)、「A Parallel Priority Queue with Constant Time Operations」、 Journal of Parallel and Distributed Computing 、 49 (1): 4–21 、 CiteSeerX 10.1.1.48.3272 、 doi :10.1006/jpdc.1998.1425
^ Osipov, Vitaly; Sanders, Peter; Singler, Johannes (2009), 「フィルタ-クラスカル最小全域木アルゴリズム」, 第11回アルゴリズム工学実験ワークショップ (ALENEX) の議事録. Society for Industrial and Applied Mathematics : 52– 61, CiteSeerX 10.1.1.218.2574
^ サンダース、ピーター. 「アルゴリズムエンジニアリングスクリプト」 (PDF) . アルゴリズムエンジニアリングKITホームページ. 2019年 2月25日 閲覧 。
^ Sanders, Peter. 「並列アルゴリズムスクリプト」 (PDF) . 並列アルゴリズムKITホームページ. 2019年 2月25日 閲覧 。
^ Zadeh, Reza. 「分散アルゴリズムと最適化」 (PDF) . 分散アルゴリズムと最適化 スタンフォード大学ホームページ. 2019年 2月25日 閲覧 。
^ Chun, Sun; Condon, Anne (1996). 「Bouvkaの最小全域木アルゴリズムの並列実装」. 国際並列処理会議論文集 . pp. 302– 308. doi :10.1109/IPPS.1996.508073. ISBN 0-8186-7255-2 . S2CID 12710022。
^ Chong, Ka Wong; Han, Yijie; Lam, Tak Wah (2001)、「並行スレッドと最適な並列最小スパニングツリーアルゴリズム」、 Journal of the Association for Computing Machinery 、 48 (2): 297– 323、 CiteSeerX 10.1.1.32.1554 、 doi :10.1145/375827.375847、 MR 1868718、 S2CID 1778676
^ ペティ、セス、ラマチャンドラン、ヴィジャヤ (2002)、「最小全域森林を見つけるためのランダム化時間作業最適並列アルゴリズム」 (PDF) 、 SIAM Journal on Computing 、 31 (6): 1879– 1895、 doi :10.1137/S0097539700371065、 MR 1954882
^ Bader, David A. ; Cong, Guojing (2006)、「疎グラフの最小全域森を計算するための高速共有メモリアルゴリズム」、 Journal of Parallel and Distributed Computing 、 66 (11): 1366– 1378、 doi :10.1016/j.jpdc.2006.06.001
^ Dementiev, Roman; Sanders, Peter; Schultes, Dominik; Sibeyn, Jop F. (2004), "Engineering an external memory minimum spanning tree algorithm", Proc. IFIP 18th World Computer Congress, TC1 3rd International Conference on Theoretical Computer Science (TCS2004) (PDF) , pp. 195– 208, 2011-08-09に オリジナル (PDF)からアーカイブ, 2019-05-24 取得 。