HUBO の QUBO への変換
HUBO(高次の制約なし二値最適化)の式は 3 次以上の項を含みうるのに対し、 QUBO(二次の制約なし二値最適化)の式は次数が 2 以下に制限されます。
QUBO++ 同梱の 3 つのソルバー(EasySolver・ExhaustiveSolver・ABS3Solver)は HUBO をそのまま扱えるため変換は不要です。しかし、外部のバックエンドの多く — 物理アニーラや Gurobi・SCIP・D-Wave などの QUBO 専用オプティマイザ — は二次の モデルしか受け付けません。これらに渡すには、HUBO を等価な QUBO に書き換える 必要があります。
reduce() 関数はこの変換を行います。次数が 2 を超えるすべての項を、新しい 補助二値変数を導入して次数 2 以下の式に書き換えます。
reduce() 関数
reduce() はグローバル関数(非破壊)とメンバ関数(in-place)の両方が提供されます。
qbpp::reduce(f)はfと等価な次数 2 以下の新しい式を返します。f.reduce()はfをその場で更新して返します。qbpp::reduce(a)は式のArrayも受け付けます(要素ごとに変換)。
#include <qbpp/qbpp.hpp>
int main() {
auto a = qbpp::var("a");
auto b = qbpp::var("b");
auto c = qbpp::var("c");
qbpp::Expr f = a * b * c; // 3 次(cubic)の HUBO 項
qbpp::Expr g = qbpp::reduce(f); // 等価な QUBO
std::cout << "f = " << f << std::endl;
std::cout << "g = " << g << std::endl;
std::cout << "max_degree = " << g.max_degree() << std::endl;
}
このプログラムの出力:
f = a*b*c
g = {r0} +a*b +a*c -a*{r0} +b*c -b*{r0} -c*{r0}
max_degree = 2
3 次の項 a*b*c が二次の式になりました。{r0} は新たに導入された補助二値変数です。 reduce() は補助変数を {r0}・{r1}・… と波括弧付きで自動命名するため、ユーザー 変数と衝突しません。
等価性の保証
reduce() は最適値を保存します。元の変数の任意の割当 x に対して、変換後の式を 補助変数について最小化した値が、元の HUBO の値に一致します。
したがって g の大域最小値(元の変数と補助変数をあわせた全体の最小値)は f の大域 最小値に等しく、g の最小解を元の変数に射影したものは f の最小解になります。これに より、reduce(f) を QUBO 専用バックエンドに渡し、結果を元の変数で読み取ることが安全 にできます。
変換の仕組み
reduce() は高次の各項を独立に書き換えます。次数 $d$ の項 $c\,x_1 x_2 \cdots x_d$ を考え、$S = x_1 + x_2 + \cdots + x_d$ をその変数のうち 1 である個数とします。
正の係数($c > 0$)— Ishikawa の規則
補助整数 $a \in [0, d-2]$ を導入し(内部的には約 $\lceil \log_2 (d-1) \rceil$ 個の二値変数で表現)、項を次のように書き換えます。
\[c\,x_1 x_2 \cdots x_d \;=\; \frac{c\,(S-a)(S-a-1)}{2}.\]$\tfrac{(S-a)(S-a-1)}{2} = \binom{S-a}{2}$ は $S-a \in \lbrace 0, 1\rbrace$ のとき 0、それ以外では正になります。したがって $a$ について最小化すると、元の積が再現 されます。
- すべての変数が 1($S = d$)のとき、補助整数は最大でも $a = d-2$ までしか取れず、 $S-a = 2$ で値 $\binom{2}{2} = 1$ — 積に等しい。
- どれかの変数が 0($S < d$)のとき、補助整数は $a = S$ または $a = S-1$ を取れて、 $\binom{0}{2} = \binom{1}{2} = 0$ — 積に等しい。
上限が $d-2$ である(補助整数が $d-1$ や $d$ に届かない)ことが、すべての変数が 1 の ときに値を 1 に強制する鍵です。
上の cubic の例($d = 3$)では、補助整数は単一の二値変数 {r0}(範囲 $[0,1]$)です。 上で出力した変換後の式 g について {r0} を最小化すると、任意の割当で $a\,b\,c$ が 再現されます。
| $(a,b,c)$ の 1 の個数 | $a\,b\,c$ | {r0}=0 の $g$ | {r0}=1 の $g$ | {r0} について $\min$ |
|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 0 |
| 1 | 0 | 0 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 |
| 3 | 1 | 3 | 1 | 1 |
補助変数はオプティマイザにとって「自由」で、エネルギーを最小にする値に落ち着きます。 その値において、変換後の項は元の積に等しくなります。
負の係数($c < 0$)— Freedman の規則
負の項は 1 個の補助二値変数 $w$ だけで済みます。
\[c\,x_1 x_2 \cdots x_d \;=\; c\,w\,\bigl(S - (d-1)\bigr).\]$c < 0$ なので、最小化は $|c|\,w\,(S-(d-1))$ の最大化を意味します。すべての変数が 1 の とき、$S-(d-1) = 1$ で $w = 1$ を選ぶと $c$ — 積に等しい。それ以外では $S-(d-1) \le 0$ なので $w = 0$ で 0 — やはり積に等しくなります。
補助変数の個数
reduce() は補助変数を少なく抑えます。
| 項 | 規則 | 補助二値変数 |
|---|---|---|
| 正係数・次数 $d$ | Ishikawa | 約 $\lceil \log_2 (d-1) \rceil$ 個($d=3,4$ で 1、$d=5\text{–}8$ で 2、$d=9\text{–}16$ で 3) |
| 負係数・任意の次数 | Freedman | ちょうど 1 個 |
否定リテラル
reduce() は否定リテラルを自動的に扱います。変換後の QUBO は正リテラルのみになります。 例えば 4 次の項 ~a*b*c*d は、正リテラルと 1 個の補助変数からなる二次式に変換されます。
qbpp::Expr p = (~a) * b * c * d;
qbpp::Expr q = qbpp::reduce(p); // 正リテラル + 補助変数 1 個
in-place 形式・配列形式
f.reduce() は f をその場で変換します。式の Array に対しては qbpp::reduce(arr)(または arr.reduce())が各要素を変換し、Array<Dim, Expr> を 返します。