多次元配列の合計関数
QUBO++は、変数や式の多次元配列に対する2つの合計関数を提供しています:
qbpp::sum(): 配列の全要素の合計を計算します。qbpp::vector_sum(): 最も内側(最低次元)の次元に沿った合計を計算します。 結果の配列は、入力配列より1つ少ない次元を持ちます。 入力配列の次元は2以上である必要があります。
以下のプログラムは、qbpp::sum() と qbpp::vector_sum() の違いを示しています:
#include <qbpp/qbpp.hpp>
int main() {
auto x = qbpp::var("x", 2, 3, 3);
auto y = x + 1;
for (size_t i = 0; i < 2; ++i) {
for (size_t j = 0; j < 3; ++j) {
for (size_t k = 0; k < 3; ++k) {
std::cout << "y[" << i << "][" << j << "][" << k << "] = " << y[i][j][k]
<< std::endl;
}
}
}
auto sum = qbpp::sum(y).simplify();
std::cout << "sum(y) = " << sum << std::endl;
auto vector_sum = qbpp::vector_sum(y).simplify();
for (size_t i = 0; i < 2; ++i) {
for (size_t j = 0; j < 3; ++j) {
std::cout << "vector_sum[" << i << "][" << j << "] = " << vector_sum[i][j]
<< std::endl;
}
}
}
まず、サイズ $2 \times 3 \times 3$ の変数配列 x を定義します。 次に、x の全要素に1を加えた配列 y を作成し、y の全要素を出力します。 続いて、qbpp::sum(y) を計算して出力します。 その後、qbpp::vector_sum() 関数を y に適用し、結果をサイズ $2 \times 3$ の2次元式配列 vector_sum に格納します。 最後に、vector_sum の全要素を出力します。
このプログラムは以下の出力を生成します:
y[0][0][0] = 1 +x[0][0][0]
y[0][0][1] = 1 +x[0][0][1]
y[0][0][2] = 1 +x[0][0][2]
y[0][1][0] = 1 +x[0][1][0]
y[0][1][1] = 1 +x[0][1][1]
y[0][1][2] = 1 +x[0][1][2]
y[0][2][0] = 1 +x[0][2][0]
y[0][2][1] = 1 +x[0][2][1]
y[0][2][2] = 1 +x[0][2][2]
y[1][0][0] = 1 +x[1][0][0]
y[1][0][1] = 1 +x[1][0][1]
y[1][0][2] = 1 +x[1][0][2]
y[1][1][0] = 1 +x[1][1][0]
y[1][1][1] = 1 +x[1][1][1]
y[1][1][2] = 1 +x[1][1][2]
y[1][2][0] = 1 +x[1][2][0]
y[1][2][1] = 1 +x[1][2][1]
y[1][2][2] = 1 +x[1][2][2]
sum(y) = 18 +x[0][0][0] +x[0][0][1] +x[0][0][2] +x[0][1][0] +x[0][1][1] +x[0][1][2] +x[0][2][0] +x[0][2][1] +x[0][2][2] +x[1][0][0] +x[1][0][1] +x[1][0][2] +x[1][1][0] +x[1][1][1] +x[1][1][2] +x[1][2][0] +x[1][2][1] +x[1][2][2]
vector_sum[0][0] = 3 +x[0][0][0] +x[0][0][1] +x[0][0][2]
vector_sum[0][1] = 3 +x[0][1][0] +x[0][1][1] +x[0][1][2]
vector_sum[0][2] = 3 +x[0][2][0] +x[0][2][1] +x[0][2][2]
vector_sum[1][0] = 3 +x[1][0][0] +x[1][0][1] +x[1][0][2]
vector_sum[1][1] = 3 +x[1][1][0] +x[1][1][1] +x[1][1][2]
vector_sum[1][2] = 3 +x[1][2][0] +x[1][2][1] +x[1][2][2]
同じ結果は明示的なforループでも得ることができます。 ただし、大きな配列の場合は qbpp::sum() と qbpp::vector_sum() を使用することを推奨します。これらの関数は内部でマルチスレッドを活用して計算を高速化します。
vector_sum() の軸指定
デフォルトでは、qbpp::vector_sum() は最も内側(最後)の軸に沿って合計を計算します。 qbpp::vector_sum(array, axis) で異なる軸を指定できます。 負のインデックスもサポートされています: 軸 -1 は最後の軸、-2 は最後から2番目の軸を指します。
上記と同じ $2 \times 3 \times 3$ の配列 x を使って、3つの軸それぞれに沿った合計を示します:
auto vs2 = qbpp::vector_sum(x, 2).simplify(); // 軸2に沿って合計(デフォルト)
auto vs1 = qbpp::vector_sum(x, 1).simplify(); // 軸1に沿って合計
auto vs0 = qbpp::vector_sum(x, 0).simplify(); // 軸0に沿って合計
qbpp::vector_sum(x, 2)は軸2(最も内側の軸)に沿って合計し、$2 \times 3$ の配列を生成します。これはqbpp::vector_sum(x)と同等です。
vs2[0][0] = x[0][0][0] +x[0][0][1] +x[0][0][2]
vs2[0][1] = x[0][1][0] +x[0][1][1] +x[0][1][2]
vs2[0][2] = x[0][2][0] +x[0][2][1] +x[0][2][2]
vs2[1][0] = x[1][0][0] +x[1][0][1] +x[1][0][2]
vs2[1][1] = x[1][1][0] +x[1][1][1] +x[1][1][2]
vs2[1][2] = x[1][2][0] +x[1][2][1] +x[1][2][2]
qbpp::vector_sum(x, 1)は軸1(中間の軸)に沿って合計し、$2 \times 3$ の配列を生成します。
vs1[0][0] = x[0][0][0] +x[0][1][0] +x[0][2][0]
vs1[0][1] = x[0][0][1] +x[0][1][1] +x[0][2][1]
vs1[0][2] = x[0][0][2] +x[0][1][2] +x[0][2][2]
vs1[1][0] = x[1][0][0] +x[1][1][0] +x[1][2][0]
vs1[1][1] = x[1][0][1] +x[1][1][1] +x[1][2][1]
vs1[1][2] = x[1][0][2] +x[1][1][2] +x[1][2][2]
qbpp::vector_sum(x, 0)は軸0(最も外側の軸)に沿って合計し、$3 \times 3$ の配列を生成します。
vs0[0][0] = x[0][0][0] +x[1][0][0]
vs0[0][1] = x[0][0][1] +x[1][0][1]
vs0[0][2] = x[0][0][2] +x[1][0][2]
vs0[1][0] = x[0][1][0] +x[1][1][0]
vs0[1][1] = x[0][1][1] +x[1][1][1]
vs0[1][2] = x[0][1][2] +x[1][1][2]
vs0[2][0] = x[0][2][0] +x[1][2][0]
vs0[2][1] = x[0][2][1] +x[1][2][1]
vs0[2][2] = x[0][2][2] +x[1][2][2]