# 変数配列と配列関数
:::{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つの最適解がすべて表示されます.
:::