配列の基本演算子と関数
基本的に、配列に対する演算子と関数は要素ごとに適用されます。
配列の基本演算子
基本演算子 +、-、*、/ は変数や式の配列に対して使用できます。
QUBO++では、これらの演算子は要素ごとに適用されます。
配列とスカラーの演算
配列とスカラーを組み合わせると、スカラーが配列の各要素に適用されます。 例えば、x がサイズ3の配列の場合:
2 * xは[2*x[0], 2*x[1], 2*x[2]]を生成x + 1は[x[0] + 1, x[1] + 1, x[2] + 1]を生成
以下のプログラムはこの動作を示しています。
import pyqbpp as qbpp
x = qbpp.var("x", shape=3)
f = 2 * x + 1
print("f =", f)
for i in range(len(f)):
print(f"f[{i}] =", f[i])
このプログラムは2値変数の配列 x = [x[0], x[1], x[2]] を作成します。 2 * x で各要素に 2 を掛け、+ 1 で各要素に 1 を加えるため、f は [1 + 2*x[0], 1 + 2*x[1], 1 + 2*x[2]] になります。 このプログラムは以下の出力を生成します。
f = [1 +2*x[0], 1 +2*x[1], 1 +2*x[2]]
f[0] = 1 +2*x[0]
f[1] = 1 +2*x[1]
f[2] = 1 +2*x[2]
配列同士の演算
同じサイズの2つの配列を組み合わせると、各インデックスで要素ごとに演算が行われます。
以下の例では、どちらもサイズ3の2つの配列 x と y を使用しています。
import pyqbpp as qbpp
x = qbpp.var("x", shape=3)
y = qbpp.var("y", shape=3)
f = 2 * x + 3 * y + 1
print("f =", f)
for i in range(len(f)):
print(f"f[{i}] =", f[i])
ここでは:
2 * xは[2*x[0], 2*x[1], 2*x[2]]になる3 * yは[3*y[0], 3*y[1], 3*y[2]]になる- 加算は要素ごとに行われるため、
i番目の要素は2*x[i] + 3*y[i] + 1も要素ごとに適用される
したがって、f は [1 + 2*x[0] + 3*y[0], 1 + 2*x[1] + 3*y[1], 1 + 2*x[2] + 3*y[2]] となり、出力と一致します。
f = [1 +2*x[0] +3*y[0], 1 +2*x[1] +3*y[1], 1 +2*x[2] +3*y[2]]
f[0] = 1 +2*x[0] +3*y[0]
f[1] = 1 +2*x[1] +3*y[1]
f[2] = 1 +2*x[2] +3*y[2]
配列同士の演算は同じ配列サイズが必要です。
次の例は、配列とスカラーの演算、配列同士の演算、単項マイナス、括弧を含む、より複雑な要素ごとの式を示しています。
import pyqbpp as qbpp
x = qbpp.var("x", shape=3)
y = qbpp.var("y", shape=3)
f = 6 * -(x + 1) * (y - 1)
g = f / 3
print("f =", f)
for i in range(len(x)):
print(f"f[{i}] =", f[i])
print("g =", g)
for i in range(len(x)):
print(f"g[{i}] =", g[i])
この例でも、すべての演算は要素ごとに適用されます。
- まず、
x + 1とy - 1は各要素にスカラーを加減算し、2つの配列[x[i]+1]と[y[i]-1]を生成します。 - 単項マイナス -(x + 1) も要素ごとに適用され、
[-(x[i]+1)]になります。 - 乗算
6 * -(x + 1) * (y - 1)も要素ごとに行われ、各インデックスiでf[i]=6*(-(x[i]+1))*(y[i]-1)となります。 この式を展開するとf[i]=6-6x[i]y[i]+6x[i]-6y[i]となり、出力と一致します。 - 最後に、
g = f / 3は各要素を3で割るため、g[i]=f[i]/3=2-2x[i]y[i]+2x[i]-2y[i]となり、やはり出力と一致します。f = [6 -6*x[0]*y[0] +6*x[0] -6*y[0], 6 -6*x[1]*y[1] +6*x[1] -6*y[1], 6 -6*x[2]*y[2] +6*x[2] -6*y[2]] f[0] = 6 -6*x[0]*y[0] +6*x[0] -6*y[0] f[1] = 6 -6*x[1]*y[1] +6*x[1] -6*y[1] f[2] = 6 -6*x[2]*y[2] +6*x[2] -6*y[2] g = [2 -2*x[0]*y[0] +2*x[0] -2*y[0], 2 -2*x[1]*y[1] +2*x[1] -2*y[1], 2 -2*x[2]*y[2] +2*x[2] -2*y[2]] g[0] = 2 -2*x[0]*y[0] +2*x[0] -2*y[0] g[1] = 2 -2*x[1]*y[1] +2*x[1] -2*y[1] g[2] = 2 -2*x[2]*y[2] +2*x[2] -2*y[2]
配列の複合演算子
同様に、複合演算子 +=、-=、*=、/= も変数や式の配列に対して使用できます。 以下の例は、サイズ3の配列に対するこれらの演算子の動作を示しています。
import pyqbpp as qbpp
x = qbpp.var("x", shape=3)
y = qbpp.var("y", shape=3)
f = 6 * x + 4
f += 3 * y
print("f =", f)
f -= 12
print("f =", f)
f *= 2 * y
print("f =", f)
f /= 2
print("f =", f)
このプログラムは以下の出力を生成します。
f = [4 +6*x[0] +3*y[0], 4 +6*x[1] +3*y[1], 4 +6*x[2] +3*y[2]]
f = [-8 +6*x[0] +3*y[0], -8 +6*x[1] +3*y[1], -8 +6*x[2] +3*y[2]]
f = [12*x[0]*y[0] +6*y[0]*y[0] -16*y[0], 12*x[1]*y[1] +6*y[1]*y[1] -16*y[1], 12*x[2]*y[2] +6*y[2]*y[2] -16*y[2]]
f = [6*x[0]*y[0] +3*y[0]*y[0] -8*y[0], 6*x[1]*y[1] +3*y[1]*y[1] -8*y[1], 6*x[2]*y[2] +3*y[2]*y[2] -8*y[2]]
配列の2乗関数
2乗関数も配列に対して使用できます。以下に例を示します。
import pyqbpp as qbpp
x = qbpp.var("x", shape=3)
f = x + 1
print("f =", qbpp.sqr(f))
print("f =", f)
f.sqr()
print("f =", f)
このプログラムは以下の出力を生成します。
f = [1 +x[0]*x[0] +x[0] +x[0], 1 +x[1]*x[1] +x[1] +x[1], 1 +x[2]*x[2] +x[2] +x[2]]
f = [1 +x[0], 1 +x[1], 1 +x[2]]
f = [1 +x[0]*x[0] +x[0] +x[0], 1 +x[1]*x[1] +x[1] +x[1], 1 +x[2]*x[2] +x[2] +x[2]]
配列の簡約化関数
簡約化関数も配列に対して使用できます。以下に例を示します。
import pyqbpp as qbpp
x = qbpp.var("x", shape=3)
f = qbpp.sqr(x - 1)
print("f =", f)
print("simplified(f) =", qbpp.simplify(f))
print("simplified_as_binary(f) =", qbpp.simplify_as_binary(f))
print("simplified_as_spin(f) =", qbpp.simplify_as_spin(f))
このプログラムは以下の出力を生成します。
f = [1 +x[0]*x[0] -x[0] -x[0], 1 +x[1]*x[1] -x[1] -x[1], 1 +x[2]*x[2] -x[2] -x[2]]
simplified(f) = [1 -2*x[0] +x[0]*x[0], 1 -2*x[1] +x[1]*x[1], 1 -2*x[2] +x[2]*x[2]]
simplified_as_binary(f) = [1 -x[0], 1 -x[1], 1 -x[2]]
simplified_as_spin(f) = [2 -2*x[0], 2 -2*x[1], 2 -2*x[2]]
注釈 これらの演算子と関数は 多次元配列 に対しても使用できます。