Jupyter Notebookで実行する
サンプルコード$n$ 変数の二値変数多項式 $f_n$ は次のように表されます。
$\displaystyle f_n(x_1, x_2, \cdots, x_n) = \sum_{\{k_1,k_2, \cdots, k_n\}}a_{k_1k_2\cdots k_n}x_1^{k_i}x_2^{k_2}\cdots x_n^{k_n}\,\quad k_i\in\{0, 1\}$
$x_i$ は二値変数で、バイナリ変数 $q_i \in \{0,1\}$ 、またはイジング変数 $s_i \in \{−1, +1\}$です。また、$a_{k_1k_2\cdots k_n}$ は多項式の係数です。
Amplify では、二値多変数多項式を表現するために以下の多項式クラスが提供されています。
BinaryPoly
(バイナリ変数による多項式)IsingPoly
(イジング変数による多項式)Amplify では SymbolGenerator
を用いることによって二値変数を多次元配列の形式で生成することができます。また、生成した二値変数に対して積*
や和+
の演算を用いることで多項式を生成できます。
from amplify import (
SymbolGenerator,
BinaryPoly,
IsingPoly,
)
# 4要素の1次元配列のバイナリ変数
gen_b = SymbolGenerator(BinaryPoly)
q_1d = gen_b.array(4)
print(q_1d)
# 3x2 の 2次元配列型のイジング変数
gen_i = SymbolGenerator(IsingPoly)
s_2d = gen_i.array(3, 2)
print(s_2d)
定義した変数を用いて多項式を生成したり、多項式を使った演算を行うことも可能です。
gen = SymbolGenerator(BinaryPoly)
q = gen.array(4)
# q_0 * q_1 + q_2
f0 = q[0] * q[1] + q[2]
# q_1 + q_3 + 1
f1 = q[1] + q[3] + 1
# (q_0 * q_1 + q_2) + (q_1 + q_3 + 1)
f2 = f0 + f1
# (q_1 + q_3 + 1) * (q_1 + q_3 + 1)
f3 = f1**2
print(f"f0 = {f0}")
print(f"f1 = {f1}")
print(f"f2 = {f2}")
print(f"f3 = {f3}")
複数の配列を生成することも可能です。先ほどの変数ジェネレータ SymbolGenerator
を用いて、何度でも array() メソッドを呼び出すことが出来ます。
from amplify import BinaryPoly, SymbolGenerator
# BinaryPoly の変数ジェネレータを定義
gen = SymbolGenerator(BinaryPoly) # BinarySymbolGenerator を用いても同様
q1 = gen.array(4, 4) # 4 x 4 の変数配列を生成
q2 = gen.array(shape=(2, 3)) # 2 x 3 の変数配列を生成
print(q1)
print(q2)
変数配列 q1
と q2
の実体は異なるインデックスであることに注意してください。変数配列を生成する度に、実体のインデックスは一つずつ増加していきます。つまり、異なる変数配列は異なる変数の集合として扱われます。
from amplify import sum_poly, BinarySymbolGenerator
# バイナリ変数を1次元配列形式に8個生成
gen = BinarySymbolGenerator()
q = gen.array(8)
print(q)
# 二値変数や多項式のリストを指定すると、その総和を計算
f0 = sum_poly(q)
print(f"f0 = {f0}")
# バイナリ変数を3個生成
gen = BinarySymbolGenerator()
q = gen.array(3)
print(q)
# インデックスを受け取る関数とインデックスの上限値を指定して、総和を取ることも可能
f1 = sum_poly(3, lambda i: sum_poly(3, lambda j: q[i] * q[j]))
print(f"f1 = {f1}")
# 2x2のバイナリ変数を生成
gen = BinarySymbolGenerator()
q = gen.array(2, 2)
print(q)
# 2乗と四則演算を含む数式の2重和
f2 = sum_poly(2, lambda i: (sum_poly(2, lambda j: q[i, j]) - 1) ** 2)
print(f"f2 = {f2}")
from amplify import pair_sum
# バイナリ変数を3個生成
gen = BinarySymbolGenerator()
q = gen.array(3)
print(q)
f3 = pair_sum(q)
print(f"f3 = {f3}")
from amplify import product
# バイナリ変数を3個生成
gen = BinarySymbolGenerator()
q = gen.array(3)
print(f"q = {q}")
f4 = product(q)
print(f"f4 = {f4}")
多項式のコンストラクタBinaryPoly
とIsingPoly
から直接多項式を構築することも可能です。
二値多変数多項式の任意の項を作るには、上記のクラスのコンストラクタの引数に以下の形式の辞書を入れます。
$kx_{i}x_{j}\cdots x_{m} \rightarrow $ {(i, j, ..., m): k}
複数の項は辞書の形にまとめることもできます。
$k_2 x_ix_j + k_1 x_l + c \rightarrow $ {(i, j): k2, (l): k1, (): c)}
以下に基本的な例を示します。
from amplify import BinaryPoly
# q_0
f0 = BinaryPoly({(0): 1})
# 2 * q_0 * q_1 + 1
f1 = BinaryPoly({(0, 1): 2, (): 1})
print(f"f0 = {f0}")
print(f"f1 = {f1}")
イジング多項式を扱う際には IsingPoly を使います。
from amplify import IsingPoly
# s_0
f0 = IsingPoly({(0): 1})
# 2 * s_0 * s_1 + 1
f1 = IsingPoly({(0, 1): 2, (): 1})
print(f"f0 = {f0}")
print(f"f1 = {f1}")