# 式クラス
:::{container} prog-cpp
Hi-QUBOの最も重要な機能は,組合せ最適化問題を解くための式を作成する能力です.
この目的のために以下の3つのクラスが使用されます.
| クラス | 内容 | 詳細 |
|------|-----|-----|
| `qbpp::Var` | 変数 | 32ビットIDと表示用文字列 |
| `qbpp::Term` | 積の項 | 0個以上の変数と整数係数 |
| `qbpp::Expr` | 式,整数変数,制約式のいずれか | 項 + 整数定数項(必要に応じて追加メタデータ) |
`qbpp::Expr` オブジェクトは生成方法によって以下のいずれかを格納します:
| 格納する内容 | 生成方法 | 追加のメタデータ |
|------------|---------|---------------|
| 式 | `x + 2*y`, `qbpp::expr(...)` など | なし |
| 整数変数 | `0 <= qbpp::var_int("x") <= 10` など | 範囲 `[min, max]`,binary 変数列,係数 |
| 制約式 | `e == 5`, `0 <= e <= 10` など | penalty(`Expr` 自身) + body(元の式) |
いずれの形も同一の `qbpp::Expr` 型なので,どの内容を格納していても同じ算術・関数が同様に使えます.
## `qbpp::Var` クラス
このクラスのインスタンスは **変数をシンボリックに** 表現します.
多くの場合,2値変数を表現するために使用されます.
ただし,このクラスは特定の変数属性に関連付けられておらず,そのインスタンスは任意の型の変数をシンボリックに表現するために使用できます.
各 qbpp::Var インスタンスは単純に以下で構成されます.
- **一意の32ビットID**
- **表示用の文字列**
例えば,以下のプログラムは `qbpp::Var` オブジェクト **`x`** を作成します.自動生成されたIDが割り当てられ,表示には文字列 `"x"` が使用されます.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
これは単に `x` と出力します.
変数シンボルと同じ文字列を使用することが推奨されますが,異なる表示文字列を使用することもできます.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
これは `symbol_x` と出力します.
## `qbpp::Term` クラス
このクラスのインスタンスは以下を含む **積の項** を表現します.
- **整数係数**
- **0個以上の `qbpp::Var` オブジェクト**
例えば,以下のプログラムは整数係数 `2` と変数 `x`,`y` を持つ `qbpp::Term` オブジェクト **`t`** を作成します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
## `qbpp::Expr` クラス
このクラスのインスタンスは,生成方法に応じて以下の 3 つの形を表現できます.
- **式** — 整数定数項と 0 個以上の `qbpp::Term` の和
- **整数変数** — 指定された整数範囲の値をとり,内部的にバイナリ変数列で表現される
- **制約式** — 比較演算子や範囲演算子で生成され,penalty と body の 2 つを保持する
いずれも同一の `qbpp::Expr` 型であり,どの形を保持していても算術演算や関数を共通に使えます.
### 式
このクラスのインスタンスは以下を含む **式** を表現します.
- **整数定数項**
- **0個以上の `qbpp::Term` オブジェクト**
例えば,以下のプログラムは定数項 `3` と項 `2*x*y` および `3*x` を持つ **`qbpp::Expr`** オブジェクト **`f`** を作成します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
式は **`+`**,**`-`**,**`*`** などの基本演算子と,括弧 **`(`** および **`)`** を使って記述できます.
式は自動的に展開され,`qbpp::Expr` オブジェクトとして格納されます.
例えば,以下のプログラムは展開された式を格納する **`qbpp::Expr`** オブジェクト **`f`** を作成します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
これらの数学的操作は式を展開するだけであることに注意してください.
式を簡約化するには,以下に示すように明示的に簡約化関数を呼び出す必要があります.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
利用可能な簡約化関数と演算子の詳細については,[基本演算子と関数](../advanced/basic-operators-and-functions.md)を参照してください.
### 整数変数
`qbpp::Expr` は**整数変数**も表現でき,指定された整数範囲の値をとります.内部的には複数のバイナリ `qbpp::Var` でエンコードされています.
整数変数は範囲チェーン構文で作成します:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
基礎となる線形式(2のべき乗で重み付けされたバイナリ変数とオフセット)が出力されます:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
整数変数はそのまま `qbpp::Expr` なので,式が期待される場所でそのまま使用できます:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
埋め込みの式に加えて,整数変数は `min_val()`,`max_val()`,および基礎となるバイナリ `Var` のメタデータを保持します.詳細と使用例は [整数変数](../basic/integer-variables-and-linear-systems.md) を参照してください.
### 制約式
`qbpp::Expr` は,式に比較演算子や範囲演算子を適用した結果として得られる**制約式**も表現できます.制約式は 2 つの部分を保持します:
- **penalty**: 制約が満たされるとき 0 となり,そうでないとき正の値をとる `Expr`
- **body**: 元の式(`ee.body()` で取得,解における実際の値を確認する際に便利)
典型的な構築方法:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
制約式はそのまま算術式として使え,算術文脈ではその penalty 部分として振る舞います:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
評価前の body にアクセスするには `ee.body()` を使います(例えば `ee.body(sol)` で解における body の値を取得).詳細と対応する比較構文の一覧は [比較演算子](../advanced/comparison-operators.md) を参照してください.
## 式に関する重要な注意事項
`qbpp::Term` クラスは `qbpp::Expr` よりも単純なデータ構造を持つため,メモリ使用量が少なく,操作のオーバーヘッドも低くなります.
ただし,`qbpp::Term` オブジェクトは完全な式を格納できません.
例えば,以下のHi-QUBOプログラムは `t` が `qbpp::Term` オブジェクトであるため,コンパイルエラーになります.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
`auto` で受けつつ式として格納・操作したい場合は,以下に示すように **`qbpp::toExpr()`** 関数で明示的に `qbpp::Expr` オブジェクトを作成します(`qbpp::Expr t = 2 * x * y;` のように型を明示して受けることもできます).
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムは `qbpp::Expr` オブジェクト **`t`** を作成し,以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
オブジェクトが式を格納することを意図している場合,`qbpp::toExpr()` 関数を使用して整数,変数,または項から構築することが推奨されます.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムでは,`f`,`g`,`h` はすべて `qbpp::Expr` オブジェクトとして作成されます.
`qbpp::toExpr()` を使用しない場合,それぞれ `int`,`qbpp::Var`,`qbpp::Term` 型になります.
例えば,以下のプログラムは `qbpp::Expr` オブジェクト **`f`** を使用して式をインクリメンタルに構築します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
ただし,`qbpp::toExpr()` を使用しない場合,`f` は `int` 変数となり,`+=` 演算子を適用する際にコンパイルエラーが発生します.
:::
:::{container} prog-python
PyQBPPの最も重要な機能は,組合せ最適化問題を解くための式を作成する能力です.この目的のために以下の3つのクラスが使用されます.
| クラス | 内容 | 詳細 |
|------|-----|-----|
| `pyqbpp.Var` | 変数 | 32ビットIDと表示用文字列 |
| `pyqbpp.Term` | 積の項 | 0個以上の変数と整数係数 |
| `pyqbpp.Expr` | 式,整数変数,制約式のいずれか | 項 + 整数定数項(必要に応じて追加メタデータ) |
`pyqbpp.Expr` オブジェクトは生成方法によって以下のいずれかを格納します:
| 格納する内容 | 生成方法 | 追加のメタデータ |
|------------|---------|---------------|
| 式 | `x + 2*y`, `qbpp.expr(...)` など | なし |
| 整数変数 | `qbpp.var(..., between=(l, u))` など | 範囲 `[min, max]`,binary 変数列,係数 |
| 制約式 | `qbpp.constrain(e, equal=5)`, `qbpp.constrain(e, between=(0, 10))` など | penalty(`Expr` 自身) + body(元の式) |
いずれの形も同一の `pyqbpp.Expr` 型なので,どの内容を格納していても同じ算術・関数が同様に使えます.
PyQBPP では**多くの場合これらの違いを意識する必要はありません**.Python の動的型付けが必要に応じて自動的に型変換を行います(例: `2 * x * y` は `Term` を生成,`+=` で `Expr` に昇格).ただし,内部的にどの形が使われているかを理解しておくと,エラーメッセージの解釈や高速化のヒントになります.
## `pyqbpp.Var` クラス
このクラスのインスタンスは**変数をシンボリックに**表現します.多くの場合,2値変数を表現するために使用されます.ただし,このクラスは特定の変数属性に関連付けられておらず,そのインスタンスは任意の型の変数をシンボリックに表現するために使用できます.
各 `Var` インスタンスは単純に以下で構成されます.
- **一意の32ビットID**
- **表示用の文字列**
例えば,以下のプログラムは変数 **`x`** を作成します.自動生成されたIDが割り当てられ,表示には文字列 `"x"` が使用されます.
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program1.py
:language: python
:caption: expression-class-program1.py
```
これは単に `x` と出力します.変数シンボルと同じ文字列を使用することが推奨されますが,異なる表示文字列を使用することもできます.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
これは `symbol_x` と出力します.
## `pyqbpp.Term` クラス
このクラスのインスタンスは以下を含む**積の項**を表現します.
- **整数係数**
- **0個以上の `Var` オブジェクト**
例えば,以下のプログラムは整数係数 `2` と変数 `x`,`y` を持つ積の項 **`t`** を作成します.
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program2.py
:language: python
:caption: expression-class-program2.py
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
## `pyqbpp.Expr` クラス
このクラスのインスタンスは,生成方法に応じて以下の 3 つの形を表現できます.
- **式** — 整数定数項と 0 個以上の `Term` オブジェクトの和
- **整数変数** — 指定された整数範囲の値をとり,内部的にバイナリ変数列で表現される
- **制約式** — 比較演算子や `qbpp.constrain()`(範囲は `between=`)で生成され,penalty と body の 2 つを保持する
いずれも同一の `pyqbpp.Expr` 型であり,どの形を保持していても算術演算や関数を共通に使えます.
### 式
最も基本的な形では,`Expr` のインスタンスは以下を含む**式**を表現します.
- **整数定数項**
- **0個以上の `Term` オブジェクト**
例えば,以下のプログラムは定数項 `3` と項 `2*x*y` および `3*x` を持つ式 **`f`** を作成します.
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program3.py
:language: python
:caption: expression-class-program3.py
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
式は **`+`**, **`-`**, **`*`** などの基本演算子と,括弧 **`(`** および **`)`** を使って記述できます.
式は自動的に展開され,`Expr` オブジェクトとして格納されます.例えば,以下のプログラムは展開された形を格納する式 **`f`** を作成します.
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program4.py
:language: python
:caption: expression-class-program4.py
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
これらの数学的操作は式を展開するだけであることに注意してください.式を簡約化するには,以下に示すように明示的に簡約化関数を呼び出す必要があります.
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program5.py
:language: python
:caption: expression-class-program5.py
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
利用可能な簡約化関数と演算子の詳細については,[基本演算子と関数](../advanced/basic-operators-and-functions.md)を参照してください.
### 整数変数
`pyqbpp.Expr` は**整数変数**も表現でき,指定された整数範囲の値をとります.内部的には複数のバイナリ変数でエンコードされています.整数変数は `qbpp.var()` に `between=` 引数を渡して作成します:
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program6.py
:language: python
:caption: expression-class-program6.py
```
基礎となる線形式(2のべき乗で重み付けされたバイナリ変数とオフセット)が出力されます:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
整数変数はそのまま `pyqbpp.Expr` なので,式が期待される場所でそのまま使用できます:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
埋め込みの式に加えて,整数変数は `min_val`,`max_val`,および基礎となるバイナリ変数のメタデータを保持します.詳細と使用例は [整数変数](../basic/integer-variables-and-linear-systems.md) を参照してください.
### 制約式
`pyqbpp.Expr` は,式に比較演算子や `qbpp.constrain()`(範囲制約は `between=`)を適用した結果として得られる**制約式**も表現できます.制約式は 2 つの部分を保持します:
- **`penalty`**: 制約が満たされるとき 0 となり,そうでないとき正の値をとる `Expr`
- **`body`**: 元の式(解における実際の値を確認する際に便利)
通常は `qbpp.constrain()` で構築します:
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program7.py
:language: python
:caption: expression-class-program7.py
```
制約式はそのまま算術式として使え,算術文脈ではその penalty 部分として振る舞います:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
評価前の式にアクセスするには `c.body` を使います(例えば解を得たあとに `sol(c.body)` で実値を確認).詳細と対応する比較構文の一覧は [比較制約](../advanced/comparison-operators.md) を参照してください.
## 式に関する重要な注意事項
`Term` クラスは `Expr` よりも単純なデータ構造を持つため,メモリ使用量が少なく,操作のオーバーヘッドも低くなります.ただし,`Term` オブジェクトは完全な式(複数項の和)を格納できません.
Python では型変換が自動的に行われるため,以下のコードでは `t += 3 * x` の時点で `t` が `Term` から `Expr` に再束縛されます:
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program8.py
:language: python
:caption: expression-class-program8.py
```
このプログラムは以下を出力します:
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
Python では `Expr` を明示的に構築する必要はありません — 算術演算子が必要に応じて `int` / `Var` / `Term` を自動的に `Expr` に昇格させます.例えば,以下のプログラムは素の `int` から始めて式をインクリメンタルに構築します.
```{literalinclude} /../programFiles/pythonPrograms/advanced/expression-class-program9.py
:language: python
:caption: expression-class-program9.py
```
このプログラムは以下を出力します.
```{include} /../programFiles/markDown/advanced/expression-class.md
:start-after:
:end-before:
```
:::