# 最大カット問題 :::{container} prog-cpp 無向グラフ $G=(V,E)$ が与えられたとき,**最大カット**問題は,ノード集合 $V$ を2つの互いに素な部分集合 $S$ と $\overline{S}$ に分割し,一方の端点が $S$ に,他方の端点が $\overline{S}$ にある $E$ の辺の数を**最大化**することを目的とします. ノードに $0,1,\ldots,n-1$ のラベルが付いているとします. $n$ 個のバイナリ変数 $x_0, x_1, \ldots, x_{n-1}$ を導入し,$x_i=1$ はノード $i$ が $S$ に属することを表します ($0\le i\le n-1$). すると,カット $(S,\overline{S})$ を横断する辺の数は以下で与えられます: $$ \begin{aligned} \text{objective} &= \sum_{(i,j)\in E}\Bigl(x_i\bar{x}_j + \bar{x}_ix_j\Bigr). \end{aligned} $$ QUBO 問題は目的関数を**最小化**するため,目的関数を**符号反転**して QUBO 式 $f$ を得ます: $$ \begin{aligned} f &= -\,\text{objective}. \end{aligned} $$ $f$ を最小化する最適な割り当ては $G$ の最大カットに対応します. また,$\text{objective}$ の値は $S$ と $\overline{S}$ の間を横断する辺の数に等しくなります. ## 最大カット問題の Hi-QUBO プログラム 上記の定式化に基づき,以下の Hi-QUBO プログラムは 16 ノードのグラフに対する QUBO 式 $f$ を構築し,Exhaustive Solver を用いて解きます: ```{literalinclude} /../programFiles/cppPrograms/example/graph/maximum-cut-program1.cpp :language: cpp :caption: maximum-cut-program1.cpp ``` このプログラムは式 `objective` と `f` を作成します.`f` は `objective` の符号反転です. Exhaustive Solver が `f` を最小化し,最適な割り当てが `sol` に格納されます. 解を可視化するために,`GraphDrawer` オブジェクト `graph` を作成し,ノードと辺を追加します. この可視化では,$S$ に属するノード $i$(つまり $x_i=1$ のノード)が着色され,カットを横断する辺が強調表示されます. このプログラムの出力は以下の通りです: ```{include} /../programFiles/markDown/example/graph/maximum-cut.md :start-after: :end-before: ``` 結果のグラフは描画され,ファイル `maxcut.svg` に保存されます: ![最大カット問題の解](../../../programFiles/images/maxcut.svg) ::: :::{container} prog-python 無向グラフ $G=(V,E)$ が与えられたとき,**最大カット問題**は,ノード集合 $V$ を2つの互いに素な部分集合 $S$ と $\overline{S}$ に分割し,一方の端点が $S$ に,他方が $\overline{S}$ に属する $E$ 中の辺の数を**最大化**することを目的とします. ノードは $0,1,\ldots,n-1$ とラベル付けされているとします. $n$ 個のバイナリ変数 $x_0, x_1, \ldots, x_{n-1}$ を導入し,$x_i=1$ はノード $i$ が $S$ に属する場合にのみ成り立ちます($0\le i\le n-1$). このとき,カット $(S,\overline{S})$ を横切る辺の数は次のように与えられます: $$ \begin{aligned} \text{objective} &= \sum_{(i,j)\in E}\Bigl(x_i\overline{x_j} + \overline{x_i}x_j\Bigr). \end{aligned} $$ QUBO 問題は目的関数を**最小化**することを目指すため,目的関数を**符号反転**して QUBO 式 $f$ を得ます: $$ \begin{aligned} f &= -\,\text{objective}. \end{aligned} $$ $f$ を最小化する最適な割り当ては,$G$ の最大カットに対応します. ## Max-Cut 問題の PyQBPP プログラム ```{literalinclude} /../programFiles/pythonPrograms/example/graph/maximum-cut-program1.py :language: python :caption: maximum-cut-program1.py ``` このプログラムは式 `objective` と `f` を作成します.`f` は `objective` の符号反転です. Exhaustive Solver が `f` を最小化し,最適な割り当てが `sol` に格納されます. このプログラムは以下の出力を生成します: ```{include} /../programFiles/markDown/example/graph/maximum-cut.md :start-after: :end-before: ``` ## matplotlib による可視化 以下のコードは `matplotlib` と `networkx` を用いて Max-Cut の解を可視化します: ```{literalinclude} /../programFiles/pythonPrograms/example/graph/maximum-cut-program2.py :language: python :caption: maximum-cut-program2.py ``` 2つの分割は赤と青で表示されます.カット辺(分割を横切る辺)は赤でハイライトされます. :::