# 変数と式
:::{container} prog-cpp
## `qbpp::Expr`で使用されるデータ型
- **`coeff_t`**:
`qbpp::Term`オブジェクトの係数に使用される整数データ型.デフォルトは`int32_t`.
- **`energy_t`**:
`qbpp::Expr`オブジェクトのエネルギー値の計算,および`qbpp::Expr`内の整数定数項に使用される整数データ型.デフォルトは`int64_t`.
`energy_t`のビット幅は`coeff_t`のビット幅以上であることが保証されています.
これらの型はプリビルド済みの共有ライブラリとセットで提供されており,
ヘッダをインクルードする前に次の `INTEGER_TYPE_*` マクロのいずれかを定義して切り替えます
(コンパイラフラグ `-D...` でも指定可能):
| マクロ | `coeff_t` | `energy_t` |
|---|---|---|
| `INTEGER_TYPE_C32E32` | `int32_t` | `int32_t` |
| `INTEGER_TYPE_C32E64`(デフォルト) | `int32_t` | `int64_t` |
| `INTEGER_TYPE_C64E64` | `int64_t` | `int64_t` |
| `INTEGER_TYPE_C64E128` | `int64_t` | `int128_t` |
| `INTEGER_TYPE_C128E128` | `int128_t` | `int128_t` |
| `INTEGER_TYPE_CPP_INT` | `cpp_int` | `cpp_int` |
> **注意 — オーバーフロー.** `coeff_t` は各係数を,`energy_t` は累積エネルギー(有効な項の総和)を制限します.固定幅の型は**オーバーフローを検出しません**.累積エネルギーが `energy_t` を超えると,C++ の組み込み整数演算と同じく**黙って折り返します**.最悪ケースのエネルギーを収められる `energy_t` を持つバリアントを選んでください.`INTEGER_TYPE_CPP_INT`(任意精度)はオーバーフローしません.
### 実数(double)係数
係数は **`double`**(実数)にもできます.`INTEGER_TYPE_*` の代わりに次の `DOUBLE_TYPE*` マクロの
いずれかを定義すると,`coeff_t` と `energy_t` はともに `double` になります:
| マクロ | `coeff_t` | `energy_t` | 求解に使うソルバー |
|---|---|---|---|
| `DOUBLE_TYPE`(= `DOUBLE_TYPE_C64E64`) | `double` | `double` | 64ビット整数ソルバー |
| `DOUBLE_TYPE_C128E128` | `double` | `double` | 128ビット整数ソルバー(高精度) |
```{literalinclude} /../programFiles/cppPrograms/quickReference/qr_variable-program1.cpp
:language: cpp
:caption: qr_variable-program1.cpp
```
- 式の構築・簡約・評価はすべて `double` で行われ,`sol.energy()` も `double` を返します.
- 求解時には係数が**自動的に整数へスケーリング**され,上記の整数ソルバーに渡されます —
手動の量子化は不要です.
- 2進小数の係数(1, 1/2, 1/4, ...)は厳密に表現されます.最大係数よりはるかに小さい係数は
スケーリング精度を下回ると通知付きでドロップされます.`DOUBLE_TYPE_C128E128` を使うと
ダイナミックレンジが大幅に広がります.
- 除算(`/`, `/=`)は実数除算です — 整数バリアントの割り切れ要件は適用されません.
- `MAXDEG*` は整数バリアントと同様に組み合わせ可能です(例: `DOUBLE_TYPE` + `MAXDEG2`).
- 定数配列や `qbpp::einsum` にも `double` 値を渡せます([MULTIDIM](../advanced/multi-dimensional-variables-and-expressions.md) / [EINSUM](../advanced/Einstein-sum.md) 参照).
詳しくは [実数(double)係数](../basic/variables-and-expressions.md#実数double係数) を参照してください.
さらに,各 `qbpp::Term` が変数をどう格納するかを制御する `MAXDEG*` マクロも指定できます.
最大次数が事前に分かっている場合,固定長モードを使うとヒープ確保が不要になり性能が向上します:
| マクロ | 最大次数 | 説明 |
|---|---|---|
| `MAXDEG0`(デフォルト) | 無制限 | 可変長(3次以上でヒープ確保) |
| `MAXDEG2` | 2 | 固定長,QUBO専用(ヒープ確保なし,最速) |
| `MAXDEG4` | 4 | 固定長,4次まで(ヒープ確保なし) |
`INTEGER_TYPE_*` と `MAXDEG*` は独立に組み合わせ可能です.詳細は [VAREXPR](../basic/variables-and-expressions.md) を参照してください.
> **WARNING**
> パフォーマンスを最大化するため,Hi-QUBOは算術オーバーフローのチェックを行いません.
> 開発およびテスト中は,`coeff_t`と`energy_t`にはより広いビット幅を使用することを推奨します.
> 必要なビット幅が不明な場合は,`qbpp::cpp_int`を使用して正確性を確保し,
> 検証後に固定幅の整数型に切り替えてください.
## クラスオブジェクトの出力
Hi-QUBOのほとんどのクラスは,`std::ostream`の`<<`演算子を使用して出力でき,
デバッグに便利です.
例えば,Hi-QUBOのオブジェクト`obj`は次のように`std::cout`に出力できます:
```{include} /../programFiles/markDown/quickReference/qr_variable.md
:start-after:
:end-before:
```
この設計により,デバッガに頼ることなく内部状態を簡単に確認できます.
## 変数クラス
- **`qbpp::Var`**:
一意な32ビット整数IDを保持するクラス.
変数名はグローバルレジストリに格納され,`std::cout << x`で確認できます.
> **注意**
> `qbpp::Var`オブジェクトは変数をシンボリックに表現します.
> 特定のデータ型は関連付けられていません.
> バイナリ,スピン,その他の型の変数を表現するために使用できます.
### 変数作成関数
変数を作成するために以下の関数が提供されています:
- **`qbpp::var("name")`**:
指定された名前`"name"`を持つ`qbpp::Var`オブジェクトを作成します.
- **`qbpp::var("name", s1)`**:
ベース名`"name"`を持つ`qbpp::Var`オブジェクトの1次元配列を作成します.
各要素は`name[i]`として表現されます.
結果は1次元の変数の配列です.
- **`qbpp::var("name", s1, s2)`**:
ベース名`"name"`を持つ`qbpp::Var`オブジェクトの2次元配列(行列)を作成します.
各要素は`name[i][j]`として表現されます.
結果は2次元の変数の配列です.
- **`qbpp::var("name", s1, s2, ...)`**:
ベース名`"name"`を持つ`qbpp::Var`オブジェクトの高次元配列を作成します.
各要素は`name[i][j]...`として表現されます.
結果はN次元の変数の配列です(`N`は次元数).
> **注意**
> `"name"`が省略された場合,`"{0}"`,`"{1}"`,...のような番号付きの名前が作成順に自動的に割り当てられます.
## `qbpp::Var`メンバ関数
`qbpp::Var`のインスタンス`x`に対して,以下のメンバ関数が利用できます:
- **`uint32_t x.index()`**:
`x`の一意な整数IDを返します.
通常,Hi-QUBOプログラムでこれらのメンバ関数を明示的に呼び出す必要はありません.
## 整数変数
Hi-QUBO には 2 種類の整数変数があります.
| 種類 | 生成 | 内部表現 | 使いどころ |
|---|---|---|---|
| 整数変数 | `l <= qbpp::var_int("x") <= u` | 複数のバイナリ変数に展開 | 外部のバイナリ専用ソルバーにも渡せる |
| [ネイティブ整数変数](../basic/integer-variables-and-linear-systems.md) | `l <= qbpp::int_var("x") <= u` | 整数値をそのまま保持 | 同梱ソルバー・MIP ソルバーで数量を扱う |
**整数変数**は,範囲とビット分解のメタデータを保持する `qbpp::Expr` であり,指定された範囲の整数値を表現します.
### 整数変数作成関数
整数変数を作成するために以下の関数が提供されています:
- **`qbpp::var_int("name")`**:
内部的に使用されるヘルパーオブジェクトを返し,単体では整数変数を作成しません.
整数変数を定義するには,以下に示すように`<=`演算子を使用して範囲を指定する必要があります.
- **`l <= qbpp::var_int("name") <= u`**:
ここで`l`と`u`は整数でなければなりません.
この式は名前`"name"`を持つ整数変数の `qbpp::Expr` オブジェクトを作成し,
保持する式が範囲`[l, u]`のすべての整数を表現します.
内部的には,基礎となる式で使用される`qbpp::Var`オブジェクトも作成されます.
- **`l <= qbpp::var_int("name", s1) <= u`**:
ベース名`"name"`と同じ範囲`[l, u]`を持つ整数変数 `qbpp::Expr` の1次元配列を作成します.
各要素は`name[i]`として表現されます.
結果は1次元の整数変数の配列です.
整数変数の高次元配列は `qbpp::Var` オブジェクトと同じ方法で作成できます.
### 整数変数メンバ関数
整数変数 `x`(`qbpp::Expr`)に対して,以下のメンバ関数が利用できます:
- **`energy_t x.min_val()`**:
`x`の最小値`l`を返します.
- **`energy_t x.max_val()`**:
`x`の最大値`u`を返します.
- **`Array<1, Var> x.vars()`**:
整数変数を表現するために使用される`qbpp::Var`オブジェクト配列を返します.
- **`Array<1, coeff_t> x.coeffs()`**:
整数係数配列を返します.
以下の式は`x`に格納されている式と等価です:
```{include} /../programFiles/markDown/quickReference/qr_variable.md
:start-after:
:end-before:
```
## ネイティブ整数変数
**ネイティブ整数変数**は,整数値をそのまま保持する `qbpp::IntVar` 型です.
`qbpp::Expr` ではなく独立した型ですが,式の中で使うと自動的に `qbpp::Expr` に
変換されるため,通常の変数と同じように書けます.詳しくは
[ネイティブ整数変数](../basic/integer-variables-and-linear-systems.md)を参照してください.
### ネイティブ整数変数作成関数
- **`l <= qbpp::int_var("name") <= u`**:
名前`"name"`・範囲`[l, u]`のネイティブ整数変数 `qbpp::IntVar` を作成します.
範囲の指定は必須で,`l < u` でなければなりません.
- **`l <= qbpp::int_var("name", s1, s2, ...) <= u`**:
同じ範囲`[l, u]`を持つネイティブ整数変数の配列 `qbpp::Array` を
作成します.各要素は`name[i]`・`name[i][j]`として表現され,`x[i]`・`x[i][j]`
でアクセスします(`x(i)`・`x(i, j)` の呼び出し形も使えます).
### ネイティブ整数変数メンバ関数
ネイティブ整数変数 `x`(`qbpp::IntVar`)に対して,以下のメンバ関数が利用できます:
- **`energy_t x.lo()`**: `x`の最小値`l`を返します.
- **`energy_t x.hi()`**: `x`の最大値`u`を返します.
解 `sol` における値は `sol(x)`(または `sol.get(x)`)で取得し,
`sol.set(x, v)` で設定します.
### 変換
- **`qbpp::binarize(f)`**:
式`f`に含まれるネイティブ整数変数をバイナリエンコーディングに展開した
新しい `qbpp::Expr` を返します.MIP ソルバーは整数変数を直接扱えるため,
バイナリ変数専用の外部 QUBO ソルバーに渡すときに使います.
:::
:::{container} prog-python
## PyQBPP のデータ型
PyQBPPでは係数・エネルギー値・定数をPythonのネイティブな `int` 型で扱うため,
ユーザーコード上で `coeff_t` や `energy_t` を気にする必要はありません.
ただし,内部で使用する共有ライブラリは複数の型バリアントを備えており,
**インポート時にサブモジュールを選択する**ことで切り替えます
(デフォルトの `import pyqbpp` は `c32e64`,つまり32ビット係数・64ビットエネルギー).
```{literalinclude} /../programFiles/pythonPrograms/quickReference/qr_variable-program1.py
:language: python
:caption: qr_variable-program1.py
```
利用可能な型バリアント:
| インポート | 係数 | エネルギー | 用途 |
|---|---|---|---|
| `import pyqbpp` / `pyqbpp.c32e64` | 32ビット | 64ビット | デフォルト,最も一般的 |
| `import pyqbpp.c32e32` | 32ビット | 32ビット | 小規模問題 |
| `import pyqbpp.c64e64` | 64ビット | 64ビット | 大きな係数 |
| `import pyqbpp.c64e128` | 64ビット | 128ビット | 大きなエネルギー範囲 |
| `import pyqbpp.c128e128` | 128ビット | 128ビット | 非常に大規模な問題 |
| `import pyqbpp.cppint` | 無制限 | 無制限 | 任意精度 (`cpp_int`) |
> **注意 — オーバーフロー.** 係数の幅は各係数を,エネルギーの幅は累積エネルギー(有効な項の総和)を制限します.固定幅のバリアントは**オーバーフローを検出しません**.累積エネルギーがエネルギー幅を超えると**黙って折り返します**.エネルギーが大きくなり得る場合は,より広いバリアント(または任意精度の `pyqbpp.cppint`)を使ってください.
### 実数(double)係数
係数は **`double`**(Python の `float`)にもできます.整数バリアントの代わりに
次のサブモジュールをインポートします:
| インポート | 係数 | エネルギー | 求解に使うソルバー |
|---|---|---|---|
| `import pyqbpp.d` / `pyqbpp.double` / `pyqbpp.dc64e64` | `float` | `float` | 64ビット整数ソルバー |
| `import pyqbpp.dc128e128` | `float` | `float` | 128ビット整数ソルバー(高精度) |
```{literalinclude} /../programFiles/pythonPrograms/quickReference/qr_variable-program2.py
:language: python
:caption: qr_variable-program2.py
```
- 式の構築・簡約・評価はすべて `float` で行われ,`sol.energy` も `float` になります.
- 求解時には係数が**自動的に整数へスケーリング**され,上記の整数ソルバーに渡されます —
手動の量子化は不要です.
- 2進小数の係数(1, 1/2, 1/4, ...)は厳密に表現されます.最大係数よりはるかに小さい係数は
スケーリング精度を下回ると通知付きでドロップされます.`pyqbpp.dc128e128` を使うと
ダイナミックレンジが大幅に広がります.
- 除算(`/`, `/=`)は実数除算です — 整数バリアントの割り切れ要件は適用されません.
- VarArray モード接尾辞も通常どおり組み合わせ可能です(例: `import pyqbpp.dc64e64m2`).
- `qbpp.array()`・`qbpp.einsum()`・配列の要素ごと演算子には `float` のリストや
**numpy の ndarray** を直接渡せます([MULTIDIM](../advanced/multi-dimensional-variables-and-expressions.md) / [EINSUM](../advanced/Einstein-sum.md) 参照).
詳しくは [実数(double)係数](../basic/variables-and-expressions.md#実数double係数) を参照してください.
さらに各バリアントに VarArray モード接尾辞 `m0` / `m2` / `m4` を付けて,
`qbpp::Term` の変数格納方式を選択できます
(例: `import pyqbpp.c32e64m4 as qbpp`):
| 接尾辞 | 最大次数 | 説明 |
|---|---|---|
| (なし)/ `m0` | 無制限 | 可変長(デフォルト,3次以上でヒープ確保) |
| `m2` | 2 | 固定長,QUBO専用(ヒープ確保なし,最速) |
| `m4` | 4 | 固定長,4次まで(ヒープ確保なし) |
型バリアントはインポート時に選択し,プログラム実行中に切り替えることはできません.
詳細は [VAREXPR](../basic/variables-and-expressions.md) を参照してください.
## オブジェクトの表示
すべてのPyQBPPオブジェクトは `print()` で表示するか,`str()` で文字列に変換できます.
```{include} /../programFiles/markDown/quickReference/qr_variable.md
:start-after:
:end-before:
```
## 変数クラス
- **`pyqbpp.Var`**:
一意な32ビット整数IDを保持するクラスです.
変数名は `str(x)` で取得できます.
> **注釈**
> `pyqbpp.Var` オブジェクトは変数をシンボリックに表現します.
> 特定のデータ型は関連付けられていません.
> バイナリ変数,スピン変数,その他の種類の変数を表現するために使用できます.
### 変数作成関数
変数を作成するために以下の関数が提供されています.
- **`pyqbpp.var("name")`**:
指定された名前 `"name"` を持つ `pyqbpp.Var` オブジェクトを作成します.
- **`pyqbpp.var("name", shape=s1)`**:
基本名 `"name"` を持つバイナリ変数の1次元配列を作成します.
各要素は `name[i]` として表されます.
- **`pyqbpp.var("name", shape=(s1, s2))`**:
基本名 `"name"` を持つバイナリ変数の2次元配列(行列)を作成します.
各要素は `name[i][j]` として表されます.
- **`pyqbpp.var("name", shape=(s1, s2, ...))`**:
基本名 `"name"` を持つバイナリ変数の高次元配列を作成します.
各要素は `name[i][j]...` として表されます.
> **注釈**
> `"name"` を省略すると,作成順に `"{0}"`,`"{1}"` などの番号付き名前が自動的に割り当てられます.
### 例
```{literalinclude} /../programFiles/pythonPrograms/quickReference/qr_variable-program3.py
:language: python
:caption: qr_variable-program3.py
```
## `pyqbpp.Var` のプロパティとメソッド
`pyqbpp.Var` のインスタンス `x` に対して,以下が利用可能です.
- **`str(x)`**:
`x` の名前を文字列として返します.
## 整数変数
Hi-QUBO には 2 種類の整数変数があります.
| 種類 | 生成 | 内部表現 | 使いどころ |
|---|---|---|---|
| 整数変数 | `qbpp.var("x", between=(l, u))` | 複数のバイナリ変数に展開 | 外部のバイナリ専用ソルバーにも渡せる |
| [ネイティブ整数変数](../basic/integer-variables-and-linear-systems.md) | `qbpp.var("x", integer=(l, u))` | 整数値をそのまま保持 | 同梱ソルバー・MIP ソルバーで数量を扱う |
**整数変数**は,範囲とビット分解のメタデータを保持する `pyqbpp.Expr` であり,指定された範囲の整数値を表現します.
### 整数変数作成関数
整数変数を作成するために以下の関数が提供されています.
- **`pyqbpp.var("name", between=(l, u))`**:
ここで `l` と `u` は整数でなければなりません.
この式は名前 `"name"` を持つ整数変数の `pyqbpp.Expr` オブジェクトを作成し,
保持する式が範囲 `[l, u]` のすべての整数を表します.
内部的に,基礎となる式で使用される `pyqbpp.Var` オブジェクトも作成します.
- **`pyqbpp.var("name", shape=s1, between=(l, u))`**:
基本名 `"name"` と同じ範囲 `[l, u]` を持つ整数変数の1次元配列を作成します.
各要素は `name[i]` として表されます.
整数変数の高次元配列は,バイナリ変数と同じ方法で作成できます.
### 例
```{literalinclude} /../programFiles/pythonPrograms/quickReference/qr_variable-program4.py
:language: python
:caption: qr_variable-program4.py
```
### 整数変数のプロパティ
整数変数 `x`(`pyqbpp.Expr`)に対して,以下が利用可能です.
- **`x.min_val`** (プロパティ):
`x` の最小値 `l` を返します.
- **`x.max_val`** (プロパティ):
`x` の最大値 `u` を返します.
- **`x.vars`** (プロパティ):
整数変数を表現するために使用される `pyqbpp.Var` オブジェクトのリストを返します.
- **`x.coeffs`** (プロパティ):
整数係数のリストを返します.
以下の式は `x` に格納されている式と等価です.
```{include} /../programFiles/markDown/quickReference/qr_variable.md
:start-after:
:end-before:
```
## ネイティブ整数変数
**ネイティブ整数変数**は,整数値をそのまま保持する `IntVar` オブジェクトです.
`Expr` ではなく独立した型ですが,式の中で使うと自動的に `Expr` に変換されるため,
通常の変数と同じように書けます.詳しくは
[ネイティブ整数変数](../basic/integer-variables-and-linear-systems.md)を参照してください.
### ネイティブ整数変数作成関数
- **`qbpp.var("name", integer=(l, u))`**:
名前`"name"`・範囲`[l, u]`のネイティブ整数変数を作成します.
範囲の指定は必須で,`l < u` でなければなりません.
- **`qbpp.var("name", s1, s2, ..., integer=(l, u))`**:
同じ範囲`[l, u]`を持つネイティブ整数変数の配列を作成します.
各要素は`name[i]`・`name[i][j]`として表現され,`x[i]`・`x[i, j]`
(`x(i, j)` も可)でアクセスします.`shape=` キーワードも使えます.
### ネイティブ整数変数のプロパティ
- **`x.lo`** (プロパティ): `x` の最小値 `l` を返します.
- **`x.hi`** (プロパティ): `x` の最大値 `u` を返します.
配列 `s` には `s.shape` / `s.ndim` / `s.total` と,全要素の和を返す
`s.sum()` があります.
解 `sol` における値は `sol(x)` で取得し,`sol.set(x, v)` で設定します.
### 変換
- **`qbpp.binarize(f)`**:
式`f`に含まれるネイティブ整数変数をバイナリエンコーディングに展開した
新しい `Expr` を返します.MIP ソルバーは整数変数を直接扱えるため,
バイナリ変数専用の外部 QUBO ソルバーに渡すときに使います.
:::