Exact Cover問題
最初にExact Cover問題について説明します。
ある自然数の集合Uを考えます。またその自然数を含むいくつかのグループ
さらに、選んだグループ数を最小になるようにするものを、Smallest Exact Coverといいます。
準備
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import blueqat.wq as wq
from blueqat import vqe
QUBOの作成
解きたい問題のQUBOマトリクスを作成します。
最初に自然数の集合を
この場合、
とすると、各自然数αに対して1つのグループのみがピックアップされた場合、
これをQUBO形式に変換していきます。まず括弧の中を展開します。
$E_{A} = A \sum _ { \alpha = 1 } ^ { n } { 1 - 2\sum _ { i : \alpha \in V _ { i } } x _ { i } + ( \sum _ { i : \alpha \in V _ { i } } x _ { i } ) ^ { 2 } } $
今回
第二項は、
$ - 2\sum _ { i : \alpha \in V _ { i } } x _ { i } = - 2\sum _ { i = j, i : \alpha \in V _ { i }, j : \alpha \in V _ { j } } x _ { i } x _ {j}$
第三項についても、i = jの場合と、
$ ( \sum _ { i : \alpha \in V _ { i } } x _ { i } ) ^ { 2 } = \sum _ { i = j, i : \alpha \in V _ { i }, j : \alpha \in V _ { j } } x _ { i } x _ {j} + 2 \sum _ { i \neq j, i : \alpha \in V _ { i }, j : \alpha \in V _ { j } } x _ { i } x _ {j} $
まとめると、
となり、QUBO形式にすることができました。
U = [1,2,3,4,5,6,7,8,9,10]
A = 1
def get_qubo(V):
Q = np.zeros( (len(V), len(V)) )
for i in range(len(V)):
for j in range(len(V)):
for k in range(len(U)):
alpha = U[k]
in_Vi = V[i].count(alpha) > 0 #V[i]に存在しているか
in_Vj = V[j].count(alpha) > 0 #V[j]に存在しているか
if i == j and in_Vi:
Q[i][j] += -1
elif i < j and in_Vi and in_Vj:
Q[i][j] += 2
return Q * A
また、結果を表示する関数を定義しておきます。
def display_answer(list_x, energies = None, show_graph = False):
print("Result x:", list_x)
text = ""
for i in range(len(list_x)):
if(list_x[i]):
text += str(V[i])
print("Picked {} group(s): {}".format(sum(list_x), text))
if energies is not None:
print("Energy:", a.E[-1])
if show_graph:
plt.plot(a.E)
plt.show()
次の通り実行してみると、正しい答えが得られていることが分かります。
V = [ [1,2], [3,4,5,6], [7,8,9,10], [1,3,5], [10] ]
qubo = get_qubo(V)
result = vqe.Vqe(vqe.QaoaAnsatz(wq.pauli(qubo), step=4)).run()
answer = result.most_common(12)
print(answer)
display_answer(answer[0][0])
(((1, 1, 1, 0, 0), 0.3783998933018464), ((0, 0, 1, 1, 0), 0.19080753539598078), ((1, 0, 1, 1, 0), 0.10904143237775482), ((1, 1, 1, 0, 1), 0.0890989364939838), ((0, 0, 1, 1, 1), 0.0449279949063271), ((0, 1, 1, 1, 0), 0.030382807525070173), ((1, 1, 0, 0, 1), 0.028032010700668703), ((1, 0, 1, 1, 1), 0.025675154329096672), ((0, 0, 1, 0, 0), 0.022072489455340405), ((1, 0, 1, 0, 0), 0.014930464403380785), ((0, 0, 0, 1, 1), 0.014135096147402253), ((1, 1, 1, 1, 0), 0.0095426809095386))
Result x: (1, 1, 1, 0, 0)
Picked 3 group(s): [1, 2][3, 4, 5, 6][7, 8, 9, 10]
Vをもう少し複雑にしてみる
Vをもう少し複雑にして(2つグループを追加して)、実行してみます。
V = [ [1,2], [3,4,5,6], [7,8,9,10], [1,3,5], [10], [7,9], [2,4,6,8] ]
qubo = get_qubo(V)
result = vqe.Vqe(vqe.QaoaAnsatz(wq.pauli(qubo), step=2)).run()
answer = result.most_common(12)
print(answer)
display_answer(answer[0][0])
(((1, 1, 1, 0, 0, 0, 0), 0.0700844494957699), ((0, 0, 0, 1, 1, 1, 1), 0.0700844494957699), ((1, 1, 0, 0, 1, 1, 0), 0.0695151945834572), ((0, 0, 1, 1, 0, 0, 1), 0.0695151945834572), ((1, 1, 0, 0, 0, 0, 0), 0.03942041130713249), ((0, 0, 1, 1, 1, 1, 1), 0.03942041130713249), ((1, 0, 0, 0, 1, 1, 0), 0.031317165076161634), ((0, 1, 1, 1, 0, 0, 1), 0.031317165076161634), ((1, 1, 1, 0, 1, 0, 0), 0.02802224137437182), ((0, 0, 0, 1, 0, 1, 1), 0.02802224137437182), ((1, 0, 1, 0, 0, 0, 0), 0.02728514456746815), ((0, 1, 0, 1, 1, 1, 1), 0.02728514456746815))
Result x: (1, 1, 1, 0, 0, 0, 0)
Picked 3 group(s): [1, 2][3, 4, 5, 6][7, 8, 9, 10]
正しい答えが得られていることが分かります。
意地悪ケース
最後に意地悪なケースを試します。
{1,2}{3}{4}{5}{6}{7}{8}{9}{10}が選ばれるのが正解です。
結果を見ると、概ね正しい答えが選ばれるようですが、まれに少しエネルギーの高い不正解の方が選ばれてしまいます。
V = [ [1,2], [3], [4], [5], [6], [7], [8], [9], [10], [2,3,4,5,6,7,8,9,10]]
for i in range(5):
print("---{}回目".format(i+1))
qubo = get_qubo(V)
result = vqe.Vqe(vqe.QaoaAnsatz(wq.pauli(qubo), step=6)).run()
answer = result.most_common(12)
display_answer(answer[0][0])
---1回目
Result x: (1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
Picked 9 group(s): [1, 2][3][4][5][6][7][8][9][10]
---2回目
Result x: (1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
Picked 9 group(s): [1, 2][3][4][5][6][7][8][9][10]
---3回目
Result x: (1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
Picked 2 group(s): [1, 2][2, 3, 4, 5, 6, 7, 8, 9, 10]
---4回目
Result x: (1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
Picked 9 group(s): [1, 2][3][4][5][6][7][8][9][10]
---5回目
Result x: (1, 0, 0, 0, 0, 0, 0, 0, 0, 1)
Picked 2 group(s): [1, 2][2, 3, 4, 5, 6, 7, 8, 9, 10]