# 比較演算子 :::{container} prog-cpp Hi-QUBO は、制約条件を作成するために 2 種類の演算子をサポートしています。 ::: :::{container} prog-python pyQUBO は、制約条件を作成するために 2 種類の演算子をサポートしています。 ::: - **等号演算子(Equality operator)**: $f=n$ の形式で、$f$ は式、$n$ は整数です。 - **範囲演算子(Range operator)**: $l \leq f \leq u$ の形式で、$f$ は式、$l$ と $u$ $(l \leq u)$ は整数です。 これらの演算子は、**対応する制約が満たされる場合にのみ最小値 0 を取る式を返します。** ## 等号演算子 等号演算子 $f=n$ は次の式を生成します: $$ (f-n)^2. $$ この式は、等式 $f=n$ が満たされる場合にのみ最小値 0 を取ります。 次のプログラムは、**Exhaustive Solver** を使って $a+2b+3c=3$ を満たすすべての解を探索します。 :::{container} prog-cpp ```{literalinclude} ../../programFiles/cppPrograms/advanced/comparison-operators-program1.cpp :language: cpp :caption: comparison-operators-program1.cpp ``` このプログラムでは、`f` は内部的に 2 つの `qbpp::Expr` オブジェクトを保持しています: - `f`: $(a+2b+3c-3)^2$. これは等式 $a+2b+3c=3$ が成立する場合に最小値 0 を取ります。 - `f.body()`: $a+2b+3c$. これは等式の左辺です。 `f` によって作成された `Exhaustive Solver` オブジェクトを使用することで、すべての最適解は `sols` に格納されます。`sols` を反復処理することで、すべての解と `f` および `f.body()` の値が次のように出力されます: ::: :::{container} prog-python ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program1.py :language: python :caption: comparison-operators-program1.py ``` このプログラムでは、`f` は内部的に 2 つの `Expr` オブジェクトを保持しています: `f`: $(a+2b+3c-3)^2$. これは等式 $a+2b+3c=3$ が成立する場合に最小値 0 を取ります。 `f.bofy`: $a+2b+3c$. これは等式の左辺です。 `f` によって作成された `Exhaustive Solver` オブジェクトを使用することで、すべての最適解は `sols` に格納されます。`sols` を反復処理することで、すべての解と `f` および `f.body` の値が次のように出力されます: ::: ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` これらの結果から、2 つの最適解が `f = 0` を達成し、`f.body = 3` を満たしていることが確認できます。 ## サポートされている等式形式に関する注意 :::{container} prog-cpp Hi-QUBO は等式演算子を次の形式でのみサポートしています: ::: :::{container} prog-python pyQBPP は等式演算子を次の形式でのみサポートしています: ::: - `expression == integer`. サポートされていない形式は以下の通りです: - `integer == expression`, - `expression1 == expression2`. `expression1 == expression2` の代わりに、制約を次のように書き換えることができます: - `expression1 - expression2 == 0`. これは完全にサポートされています。 ## 範囲演算子 $l \leq f \leq u~(l \leq u)$ の形の範囲演算子は、制約が満たされる場合に限り、最小値 0 をとる式を生成します。 ここでは、$l$ と $u$ の値に応じて、以下のケースを考えます。 - Case1: $u=l$, - Case2: $u=l+1$, - Case3: $u=l+2$, - Case4: $u \geq l+3$. ### Case1: $u=l$ もし $u=l$ であれば、範囲制約は等式制約 $f=l$ に帰着します。この制約は、等号演算子を用いて直接実装できます。 ### Case2: $u=l+1$ もし $u=l+1$ の場合、次の式が生成されます。 $$ (f-l)(f-u). $$ $l :::{container} prog-cpp ## 4つのケースに対する Hi-QUBO プログラム 次のプログラムは、4つのケースが Hi-QUBO でどのように実装されるかを示しています: ```{literalinclude} ../../programFiles/cppPrograms/advanced/comparison-operators-program2.cpp :language: cpp :caption: comparison-operators-program2.cpp ``` ::: :::{container} prog-python ## 4つのケースに対する PyQBPP プログラム 次のプログラムは、4つのケースが PyQBPP でどのように実装されるかを示しています: ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program2.py :language: python :caption: comparison-operators-program2.py ``` ::: このプログラムは次の出力を生成します: ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` これらの出力は、次の式に対応しています: $$ f_1&=(f-1)^2,\\ f_2&=(f-1)(f-2),\\ f_3&=(f-x_0)(f-(x_0+1)),\\ f_4&=(f-(2x_{10}+x_{11}+1))(f-(2x_{10}+x_{11}+2)). $$ :::{container} prog-cpp ## 範囲演算子を使用した Hi-QUBO プログラム 以下のプログラムは、Hi-QUBO における範囲演算子の使用方法を示しています。 ```{literalinclude} ../../programFiles/cppPrograms/advanced/comparison-operators-program3.cpp :language: cpp :caption: comparison-operators-program3.cpp ``` ::: :::{container} prog-python ## 範囲演算子を使用した PyQBPP プログラム 以下のプログラムは、PyQBPPにおける範囲演算子の使用方法を示しています。 ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program3.py :language: python :caption: comparison-operators-program3.py ``` ::: 3つのバイナリ変数 $a, b$ および $c$ に対して、このプログラムは次の制約を満たす解を探索します : $$ 5 \leq 4a + 9b + 15c \leq 14 $$ このプログラムは次の出力を生成します。 ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` ## 下限および上限の制約演算子 :::{container} prog-cpp Hi-QUBO は、以下の **片側境界演算子** を直接サポートしていません。 ::: :::{container} prog-python pyQBPP は、以下の **片側境界演算子** を直接サポートしていません。 ::: - **下限制約演算子:** $l \leq f$. - **上限制約演算子:** $f \leq u$. :::{container} prog-cpp その代わりに、Hi-QUBO は **無限大**($\infty$) の記号表現(`qbpp::inf`)を提供しており、これらの制約は **範囲演算子** を用いて次のように実装されます。 - **下限制約演算子:** `l <= f <= +qbpp::inf` → $l \leq f \leq +\infty$. - **上限制約演算子:** `-qbpp::inf <= f <= u` → $-\infty \leq f \leq u$. ::: :::{container} prog-python 代わりに、PyQBPP は `between` の境界値を `None` とすることでこれらをサポートします: - **下限制約演算子:** `between(l, None)` → $l \leq f \leq +\infty$. - **上限制約演算子:** `between(None, u)` → $-\infty \leq f \leq u$. ::: 範囲演算子は内部的に補助変数(auxiliary variables)を導入するため、**真の無限値を明示的に表現することはできません**。 :::{container} prog-cpp そのため、Hi-QUBO は式 $f$ の **有限の最大値および最小値** を推定し、それぞれ $+\infty$ および $-\infty$ の代替値として使用します。 ::: :::{container} prog-python そのため、pyQBPP は式 $f$ の **有限の最大値および最小値** を推定し、それぞれ $+\infty$ および $-\infty$ の代替値として使用します。 ::: 例えば、次の式を考えます : $$ f=4a+9b+11c. $$ ここで、$a,b$ そして $c$ は **バイナリ変数** です。 この式 $f$ が取り得る **最小値と最大値** はそれぞれ 0 と 24 です。 :::{container} prog-cpp したがって、Hi-QBPP は対応する範囲制約を構築する際に、0 を $-\infty$ の代替値、24 を $+\infty$ の代替値として使用します。 ::: :::{container} prog-python したがって、pyQBPP は対応する範囲制約を構築する際に、0 を $-\infty$ の代替値、24 を $+\infty$ の代替値として使用します。 :::
**NOTE** :::{container} prog-cpp Hi-QUBO では、不等式制約において **下限と上限の両方を明示的に指定すること** を意図的に要求しています。これは次のような **解釈の曖昧さ** を避けるためです。 ::: :::{container} prog-python pyQBPP では、不等式制約において **下限と上限の両方を明示的に指定すること** を意図的に要求しています。これは次のような **解釈の曖昧さ** を避けるためです。 ::: - **MIP(Mixed Integer Programming)スタイルの解釈** - 例: $f \leq u$ が $0 \leq f \leq u$ を意味する。 - **QUBO スタイルの解釈** - 例:$f \leq u$ が $-\infty \leq f \leq u$ を意味する。 このような曖昧さは、微妙なモデリングエラーを引き起こす可能性があります。
:::{container} prog-cpp ## 下限および上限制約演算子の Hi-QUBO プログラム Hi-QUBO では、$+\infty$ は `qbpp::inf` によって表現されます。 ::: :::{container} prog-python ## 下限および上限制約演算子の pyQBPP プログラム pyQBPP では、$+\infty$ は `between` の対応する側の `None` で表現されます。 ::: 以下のプログラムは **下限制約演算子(lower-bound operator)** を示す例です。 :::{container} prog-cpp ```{literalinclude} ../../programFiles/cppPrograms/advanced/comparison-operators-program4.cpp :language: cpp :caption: comparison-operators-program4.cpp ``` このプログラムでは、`+qbpp::inf` は正の無限大の値を表しており、自動的に 24 に置き換えられます。 ::: :::{container} prog-python ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program4.py :language: python :caption: comparison-operators-program4.py ``` このプログラムでは、`between=(14, None)` の `None` は正の無限大の値を表しており、自動的に 24 に置き換えられます。 ::: このプログラムは次の出力を生成します。 ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` 次のプログラムは、**上限制約演算子** を示しています。 :::{container} prog-cpp ```{literalinclude} ../../programFiles/cppPrograms/advanced/comparison-operators-program5.cpp :language: cpp :caption: comparison-operators-program5.cpp ``` このプログラムでは、`-qbpp::inf` は負の無限大の値を表しており、自動的に 0 に置き換えられます。 ::: :::{container} prog-python ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program5.py :language: python :caption: comparison-operators-program5.py ``` このプログラムでは、`between=(None, 14)` の `None` は負の無限大の値を表しており、自動的に 0 に置き換えられます。 ::: このプログラムは次の出力を生成します。 ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` :::{container} prog-python ## 演算子による省略構文 利便性のため、PyQBPPは式と整数の間の比較演算子 `==`, `<=`, `>=` も受け付けます。 これらは `qbpp.constrain()` と同等の制約式を生成します: | 演算子による形式 | 等価な `qbpp.constrain()` 形式 | 生成される penalty | |---|---|---| | `f == n` | `qbpp.constrain(f, equal=n)` | $(f - n)^2$ | | `f <= n` | `qbpp.constrain(f, between=(None, n))` | $\min(f) \leq f \leq n$ のとき 0 | | `f >= n` | `qbpp.constrain(f, between=(n, None))` | $n \leq f \leq \max(f)$ のとき 0 | ここで $\min(f)$ と $\max(f)$ は $f$ の係数から導かれる構造的な境界であり、上記の 下界・上界制約で説明したルールに従います。反転形式 $n <= f$, $n >= f$ も Python の標準的な反射規則により動作します。 例えば、上の上界制約のプログラムは次のように書き換えられます: :::{container} prog-python ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program6.py :language: python :caption: comparison-operators-program6.py ``` これらの演算子は式の配列に対しても定義されており、その場合は要素ごとに制約が適用され、 制約式の配列が返されます。 > 注釈 右辺には `int` のみを受け付けます。`expression1 <= expression2` の形式はサポートされておらず、 `(expression1 - expression2) <= 0` に書き換えるか、`qbpp.constrain()` で `between=` 範囲を 明示的に指定してください。`var1 == var2` のような変数の同一性比較(辞書のキーとして使うために bool を返すもの)は影響を受けません。演算子オーバーロードは `Expr` および式の配列に対してのみ 定義されているためです。 ## `qbpp.same` による範囲制約の連鎖記法 `qbpp.constrain(f, between=(l, u))` を書くもう一つの方法として、上界制約と下界制約を `&` で連結する記法が用意されています。 ここで、もう一方の側にある式 `f` をプレースホルダ `qbpp.same` で参照します: ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` `<=` / `>=` の向きや左右はどの組合せでも構いません。`&` の左右どちらに `qbpp.same` を置いても解釈されます。 `qbpp.same` を介在させる理由は、`f` が大きな式や配列の場合でも、両側の制約に対して補助変数を 1 組だけ生成するためです。 `qbpp.constrain(f, between=(l, u))` と完全に同じ QUBO 式が得られます。 ## 連鎖記法のPyQBPPプログラム 以下のプログラムは、範囲制約を使用するPyQBPPプログラム と同じ制約 $5 \leq 4a+9b+15c \leq 14$ を連鎖記法で書いたものです: :::{container} prog-python ```{literalinclude} ../../programFiles/pythonPrograms/advanced/comparison-operators-program7.py :language: python :caption: comparison-operators-program7.py ``` `qbpp.constrain(4*a + 9*b + 15*c, between=(5, 14))` を使った場合と同一の出力が得られます。 ## 配列に対する連鎖記法 `qbpp.same`は式の配列に対しても使えます。配列の各要素に同じ範囲制約が適用され、制約式の配列が返されます: ```{include} ../../programFiles/markDown/advanced/comparison-operators-program.md :start-after: :end-before: ``` ### サポートされない形式 両側に同じ式を書いた `(l <= f) & (f <= u)` の形式はサポートされていません。連鎖記法では片側を `qbpp.same` にしてください。 :::