半順序を全順序に拡張するやつ
この記事は「みゅーもり Advent Calendar 2018」の11日目分となります:
記事を書く時間が十分に取れ無さそう(そもそも現時点で締切を2日超過している)なので, 計画を変更して簡単に書ける内容にしました.
(当初予定していた「banditとcoarse correlated equilibriumの関係性」の記事は(みゅーもりのやる気があれば)後日改めて書こうと思います……)
Jupyter Notebook: http://nbviewer.jupyter.org/github/myuuuuun/blog_contents/blob/master/notebooks/topological_sort.ipynb
定義
を任意の集合とし, を 上で定義された二項関係とします.
このとき が以下の3つを満たせば, は 半順序(partial order) であるといいます
- 反射律: \begin{align} x \succeq x \end{align}
- 推移律: \begin{align} x \succeq y \land y \succeq z \implies x \succeq z \end{align}
- 歪対称律: \begin{align} x \succeq y \land y \succeq x \implies x = y \end{align}
また が以下の3つを満たせば, は 全順序, または線形順序(total order / linear order) であるといいます
- 完全律: \begin{align} x \succeq y \lor y \succeq x \end{align}
- 推移律: \begin{align} x \succeq y \land y \succeq z \implies x \succeq z \end{align}
- 歪対称律: \begin{align} x \succeq y \land y \succeq x \implies x = y \end{align}
が 上の半順序である時, を 半順序集合(partially ordered set / poset) といいます. 同様に が 上の全順序である時, を 全順序集合(totally ordered set) といいます.
半順序と全順序の違いは1.のみです. 完全律が成り立てば反射律も自動的に成り立つので, 全順序集合であれば必ず半順序集合になります.
イメージ
順序関係を有向グラフで表現してみます. たとえば として, 上の二項関係を \begin{align} \forall x, y \in X, x \succeq y \Longleftrightarrow \ \text{$x = y$, または$x$から$y$へ向かうpathがある} \end{align} と定義します.
- 例1は半順序ですが, と のいずれも成り立たないため, 全順序ではありません
- 例2は全順序(したがって半順序)です. 全順序である時, 順序を崩さずに集合の各元を一列に並べることができます(例では)
- 例3は ですが なので, 歪対称律を満たさず, 半順序ではありません
- 例4は, 仮に推移律を満たすとすると より となります. しかし でもあるので, 歪対称律が成り立ちません. したがって推移律と歪対称律が同時に成り立たないので, これは半順序ではありません
問題設定
半順序集合 が与えられた時, この半順序 を拡張して全順序 を構成することはできるでしょうか?
より厳密に書けば \begin{align} \forall x, y \in X, x \succeq y \implies x \succeq^{L} y \end{align} を満たす 上の全順序 は存在するでしょうか?
が有限の場合
の要素が有限個の場合は, 以下で具体的に説明するように, 半順序集合を非巡回有向グラフ(Directed Acyclic Graph, DAG)に置き換えてトポロジカルソートを実行することで, 条件を満たす全順序を具体的に構成できます.
Step 1: 半順序集合からDAGを構成する
まず半順序集合 を所与として, 次のような有向グラフ を構成します( は頂点の集合, が有向辺の集合です )
- 頂点は の各元()
- 頂点 から 頂点 への有向辺 は, \begin{align} (x, y) \in E \iff x \neq y \land x \succeq y \end{align}
このようにして作られた有向グラフ には閉路(サイクル)はありません.
(∵)仮にサイクル があったとする. グラフの構成から \begin{align} x_1 \succeq x_2, \hspace{0.5em} x_2 \succeq x_3, \hspace{0.5em} \ldots, \hspace{0.5em} x_{n-1} \succeq x_n, \hspace{0.5em} x_n \succeq x_1 \end{align} が成り立つ. は半順序なので, 推移律から が成り立つ. しかし でもあるので, よりこれは歪対称律を破り, が半順序であることに矛盾する.
に閉路が無いので, この有向グラフはDAGになっています. よって半順序集合からDAGを構成できました.
Step2: DAGにトポロジカルソートを適用する
トポロジカルソートとは, 以下のルールを満たすようDAGの各点を並び替えることを言います
どの点も, その点から有向パスが伸びている任意の点より前に並んでいる
例
下図の例でトポロジカルソートを実行すると,
などが解になります.
解はユニークではありませんが, 有向グラフに閉路が存在しなければ(DAGであれば)解は必ず1つ以上存在します. このことは次のアルゴリズムの停止条件からわかります.
アルゴリズム
深さ優先探索を応用してトポロジカルソートを実現するアルゴリズムを紹介します. 以下の擬似コードはwikipediaからのコピペです.
L ← トポロジカルソートされた結果の入る空の連結リスト for each ノード n do if n に印が付いていない then visit(n) function visit(Node n) if n に「一時的」の印が付いている then 閉路があり DAG でないので中断 else if n に印が付いていない then n に「一時的」の印を付ける for each n の出力辺 e とその先のノード m do visit(m) n に「恒久的」の印を付ける n を L の先頭に追加
補足: 深さ優先探索をする過程で「一時的」の印が付いたノードに辿り着いたということは, 探索をしてきたパスの中に閉路が存在するということです. したがってDAGであれば, visit()
の最初のifの中身が実行されることはありません.
class DiGraph(object): false_flag, temp_flag, perm_flag = 0, 1, 2 def __init__(self, nodes, edges): self.nodes = nodes self.edges = edges self.node_size = len(nodes) def topological_sort(self): self.flags = {node:self.false_flag for node in self.nodes} self.sorted_nodes = [] for node in self.nodes: if self.flags[node] == self.false_flag: self.visit(node) return self.sorted_nodes[::-1] def visit(self, node): if self.flags[node] == self.temp_flag: raise ValueError("DiGraph has a cycle") elif self.flags[node] == self.false_flag: self.flags[node] = self.temp_flag for node_to in self.edges[node]: self.visit(node_to) self.flags[node] = self.perm_flag self.sorted_nodes.append(node)
上の例を解いてみると
nodes = ["a", "b", "c", "d", "e"] edges = { "a": ["b", "c"], "b": ["d"], "c": ["d"], "d": [], "e": [], } digraph = DiGraph(nodes, edges) digraph.topological_sort()
>> ['e', 'a', 'c', 'b', 'd']
となりました.
停止条件と計算量
上述のようにDAGであればアルゴリズムが途中でエラーを出力することは無いので,
- 全ての辺を探索し()
- 全ての頂点を
sorted_nodes (L)
に追加した()
時点でアルゴリズムは終了します. したがって計算量は となります.
Step 3: トポロジカルソートの結果を全順序とする
トポロジカルソートの結果, の各元の順番が と定まったら, あとは 上の二項関係 を \begin{align} x_1 \succeq_L x_2 \succeq_L \ldots \succeq_L x_n \end{align} で定義すれば, これは を拡張した全順序になっています. なぜならば, 任意の s.t. に対し,
- DAGの構成から,
- トポロジカルソートの定義から, は よりも前に並んでいる
- の構成から,
となっているためです.
が無限の場合
の要素が無限個の場合はトポロジカルソートのアルゴリズムの停止が保証できないため, 上記のような構成的な証明は使えません.
いま上で定義された2つの半順序 と の包含関係 を \begin{align} (\succeq_1) \subseteq (\succeq_2) \iff [ \forall x, y \in X, \ x \succeq_1 y \implies x \succeq_2 y ] \end{align} と定義します(つまり は を拡張したものだということです).
また与えられた半順序集合 に対し, 「 を拡張した上の半順序」全体の集合を \begin{align} \mathcal{P} = \left\{ \succeq^{\prime} \mid \text{$\succeq^{\prime}$は$X$上の半順序} \land (\succeq) \subseteq (\succeq^{\prime}) \right\} \end{align} で定義します.
このとき, は半順序集合になっています.
(∵)半順序集合が満たすべき性質1-3を順にチェックすれば良い. と を任意に取る.
- 反射律: が成り立つので,
- 推移律: が成り立つとすると, \begin{align} x \succeq_1 y \implies x \succeq_2 y \implies x \succeq_3 y \end{align} が成り立つ. よって
- 歪対称律: が成り立つとすると, \begin{align} x \succeq_1 y \iff x \succeq_2 y \end{align} が成り立つ. よって
(∵) の(空でない)全順序部分集合 を任意に取る.
いま新たな上の二項関係 を, \begin{align} \forall x, y \in X, \ x \succeq_U y \iff x \succeq_D y \hspace{0.5em} \text{for some $(\succeq_D) \in \mathcal{D}$} \end{align} で定義する. この時
- は半順序
- は の上界
が成り立つ. まず1.に関しては, 任意の に対して
- 反射律: なので,
- 推移律: かつ だと仮定する. この時 が存在して \begin{align} x \succeq_{D1} y, \ y \succeq_{D2} z \end{align} が成り立つ. いま は全順序集合だから, 完全律より または の少なくとも一方が成り立つ. 一般性を失わず が成り立つとすると, \begin{align} x \succeq_{D1} y \implies x \succeq_{D2} y \end{align} が成り立つ. が半順序であることから, と合わせて推移律より \begin{align} x \succeq_{D2} z \end{align} が成り立つ. よって
- 歪対称律: かつ だと仮定する. この時 が存在して \begin{align} x \succeq_{D1} y, \ y \succeq_{D2} x \end{align} が成り立つ. よって推移律と全く同様の議論から, or に対して \begin{align} x \succeq_{Di} y \land y \succeq_{Di} x \end{align} が成り立つので, の歪対称律から となる
2.に関しては, すでに が半順序であることがわかったので, が成り立つことだけを調べればよい. これは , \begin{align} x \succeq y \implies \forall (\succeq_{D}) \in \mathcal{D}, x \succeq_{D} y \implies x \succeq_{U} y \end{align} より成り立つ.
3.に関しては, の構成から任意の に対して, \begin{align} \forall x, y \in X, \ x \succeq_{D} y \implies x \succeq_{U} y \end{align} となり が成り立つので, は確かに の上界となる.
したがってZornの補題が適用でき, 半順序集合 は極大元を持ちます. 極大元の1つを とすると, これは を拡張した上の全順序になっています.
(∵) なので, を拡張した上の半順序であることは明らか. したがって完全律だけを確かめれば良い.
任意の をとる. 背理法の仮定として, と のいずれも成り立たないとする. この時 上の新しい二項関係 を \begin{align} \forall v, w \in X, \ v \succeq_{M^{\prime}} w \iff \begin{cases} v \succeq_{M} w, \ \text{ or } \\ v \succeq_{M} x \land y \succeq_{M} w \end{cases}\tag{1} \end{align} で定義する(つまり に を加え, 推移律を満たすように拡張したもの).
この時 は半順序になっている. なぜならば任意の に対し,
- 反射律: の反射律から が成り立つので, もOK
- 推移律: および が成り立つと仮定する.
- の場合: かつ なので, (1)より
- の場合: かつ なので, (1)より
- その他の場合: が推移律を満たすことからOK
- 歪対称律: および が成り立つと仮定する. 背理法の仮定から なので, が歪対称律を満たすことからOK
加えて なので, . これは が の極大元であることに反する.
したがって完全律が成り立ち, は を拡張した上の全順序になっています. よって任意の半順序集合 に対して, それを拡張した全順序を構成できることがわかりました.