# 変数配列と配列関数 :::{container} prog-cpp Hi-QUBOは変数配列と配列演算をサポートしています. ## 変数配列の定義 2値変数の配列は **`qbpp::var()`** 関数を使って作成できます. - **`qbpp::var("name", size)`** は,指定した `name` を持つ `size` 個の変数の配列を返します. 以下のプログラムは,名前 **`x`** を持つ5個の変数の配列を定義します. `x` を `std::cout` で出力すると,5つの変数 **`x[0]`**,**`x[1]`**,**`x[2]`**,**`x[3]`**,**`x[4]`** が含まれていることを確認できます. 次に,**`qbpp::toExpr(0)`** を型推論とともに使用して,初期値が `0` の **`qbpp::Expr`** オブジェクト **`f`** を作成します. `i = 0` から `4` までのforループで,各変数 `x[i]` が複合演算子 **`+=`** を使って `f` に加算されます. 最後に,`f` が簡約化され,`std::cout` で出力されます. ```{literalinclude} /../programFiles/cppPrograms/basic/vector-variables-and-functions-program1.cpp :language: cpp :caption: vector-variables-and-functions-program1.cpp ``` このプログラムの出力は以下の通りです. ```{include} /../programFiles/markDown/basic/vector-variables-and-functions.md :start-after: :end-before: ``` > **注意** > **`qbpp::var(name, size)`** は `qbpp::Var` 型の `size` 個の要素を含む1次元の変数の配列を返します. > 厳密な型は **`qbpp::Array<1, qbpp::Var>`** で,`1` は次元数,`qbpp::Var` は要素の型を表します. > `auto` を使えばコンパイラがこの型を推論してくれるので,明示的に書く必要があるのは,配列を非 `static` なクラスのメンバ変数として保持する場合だけです(C++ では非 static メンバに `auto` が使えないため). > 配列の型は,要素に対する要素ごとの演算をサポートするオーバーロードされた演算子を提供します. > **注意 — インデックスの範囲** > C++ では `x[i]` は**範囲チェックを行いません**(`std::vector::operator[]` と同じ規約).範囲外や負のインデックスは未定義動作です.インデックスは `[0, size)` の範囲に収めてください.Python では範囲外インデックスに対して `x[i]` が `IndexError` を送出します. > 配列の要素ごとの演算は**同一の shape** を要求します.異なる shape の配列を組み合わせるのはエラーです(C++ では致命的エラー,Python では例外送出). ## sum 関数 配列ユーティリティ関数 **`qbpp::sum()`** を使用すると,2値変数の配列の合計を取得できます. 以下のプログラムは `qbpp::sum()` を使用して,配列 `x` のすべての変数の合計を計算します. ```{literalinclude} /../programFiles/cppPrograms/basic/vector-variables-and-functions-program2.cpp :language: cpp :caption: vector-variables-and-functions-program2.cpp ``` このプログラムの出力は,前のプログラムとまったく同じです. ## One-hot制約のQUBO 2値変数の配列が **one-hot** であるとは,**ちょうど1つの要素が1に等しい**,すなわち要素の合計が1に等しいことを意味します. $X = (x_0, x_1, \ldots, x_{n-1})$ を $n$ 個の2値変数の配列とします. 以下の式 $f(X)$ は,$X$ がone-hotである場合にのみ最小値0をとります. $$ \begin{align} f(X) &= \left(1 - \sum_{i=0}^{n-1}x_i\right)^2 \end{align} $$ 以下のプログラムは式 $f$ を作成し,すべての最適解を見つけます. ```{literalinclude} /../programFiles/cppPrograms/basic/vector-variables-and-functions-program3.cpp :language: cpp :caption: vector-variables-and-functions-program3.cpp ``` 関数 **`qbpp::sum()`** は配列内のすべての変数の合計を計算します. 関数 **`qbpp::sqr()`** は引数の2乗を計算します. Exhaustive Solverはエネルギー値0のすべての最適解を見つけ,`std::cout` で以下のように出力されます. ```{include} /../programFiles/markDown/basic/vector-variables-and-functions.md :start-after: :end-before: ``` 5つの最適解がすべて表示されます. ::: :::{container} prog-python PyQBPPは変数の配列と配列演算をサポートしています. ## 変数配列の定義 バイナリ変数の配列は **`var()`** 関数を使って作成できます. - **`var("name", shape=size)`** は,指定された `name` を持つ `size` 個の変数からなる配列を返します. 以下のプログラムは,**`x`** という名前の5個の変数からなる配列を定義します. `x` を表示すると,5つの変数 **`x[0]`**,**`x[1]`**,**`x[2]`**,**`x[3]`**,**`x[4]`** が含まれていることが確認できます. 次に,`f = 0` から始め,`i = 0` から `4` までの for ループで,各変数 `x[i]` を複合演算子 **`+=`** で `f` に加えます. 最後に,`f` を簡約化して表示します. ```{literalinclude} /../programFiles/pythonPrograms/basic/vector-variables-and-functions-program1.py :language: python :caption: vector-variables-and-functions-program1.py ``` このプログラムの出力は以下の通りです. ```{include} /../programFiles/markDown/basic/vector-variables-and-functions.md :start-after: :end-before: ``` > **注意** — `x[i]` は範囲外インデックスに対して `IndexError` を送出します.配列の要素ごとの演算は**同一の shape** を要求し,異なる shape の配列を組み合わせると例外を送出します. ## Sum 関数 ユーティリティ関数 **`sum()`** を使って,バイナリ変数配列の合計を取得できます. 以下のプログラムは `sum()` を使って配列 `x` のすべての変数の合計を計算します. ```{literalinclude} /../programFiles/pythonPrograms/basic/vector-variables-and-functions-program2.py :language: python :caption: vector-variables-and-functions-program2.py ``` このプログラムの出力は,前のプログラムとまったく同じです. ## One-hot 制約の QUBO バイナリ変数の配列が **one-hot** であるとは,**ちょうど1つの要素が1に等しい**こと,すなわち要素の合計が1に等しいことを意味します. $X = (x_0, x_1, \ldots, x_{n-1})$ を $n$ 個のバイナリ変数の配列とします. 以下の式 $f(X)$ は,$X$ が one-hot であるとき,かつそのときに限り最小値 0 をとります. $$ \begin{align} f(X) &= \left(1 - \sum_{i=0}^{n-1}x_i\right)^2 \end{align} $$ 以下のプログラムは式 $f$ を作成し,すべての最適解を求めます. ```{literalinclude} /../programFiles/pythonPrograms/basic/vector-variables-and-functions-program3.py :language: python :caption: vector-variables-and-functions-program3.py ``` 関数 **`sum()`** は配列内のすべての変数の合計を計算します. 関数 **`sqr()`** は引数の二乗を計算します. Exhaustive Solver は,エネルギー値 0 のすべての最適解を以下のように求めます. ```{include} /../programFiles/markDown/basic/vector-variables-and-functions.md :start-after: :end-before: ``` 5つの最適解がすべて表示されます. :::