基本演算子と関数

単項演算子と二項演算子

Hi-QUBOは,式(すなわちqbpp::Exprオブジェクト)を構築するための以下の基本的な二項演算子をサポートしています:

  • +: オペランドの和を返します.

  • -: オペランドの差を返します.

  • *: オペランドの積を返します.

  • /: オペランドの商を返します. 除数は整数でなければならず,被除数の定数項とすべての係数は除数で割り切れる必要があります.double フロントエンド(DOUBLE_TYPE*)では割り切れる必要はなく,係数はそのまま実数として除算されます.

  • 単項**-**: オペランドの符号を反転した値を返します.

  • 単項**~**: 変数の否定リテラル(~x = \(1-x\))を返します.詳細は変数を参照してください.

これらの演算子の優先順位は,標準的なC++の演算子優先順位規則に従います.

以下のプログラムは,これらの演算子を使用して式を構築する方法を示しています:

basic-operators-and-functions-program1.cpp
#include <qbpp/qbpp.hpp>

int main() {
  auto x = qbpp::var("x");
  auto y = qbpp::var("y");
  auto f = 6 * -(x + 1) * (y - 1);
  auto g = f / 3;

  std::cout << "f = " << f << std::endl;
  std::cout << "g = " << g << std::endl;
}

このプログラムの出力は次のとおりです:

f = 6 -6*y +6*x -6*x*y
g = 2 -2*y +2*x -2*x*y

複合演算子

qbpp::Exprオブジェクトを更新するための以下の複合演算子もサポートされています.

  • += : 右辺のオペランドを左辺に加算します.

  • -= : 右辺のオペランドを左辺から減算します.

  • *= : 右辺のオペランドを左辺に乗算します.

  • /= : 左辺のオペランドを右辺で除算します.右辺のオペランドは整数でなければならず,左辺の定数項の整数値とすべての係数は割り切れる必要があります.double フロントエンドでは割り切れる必要はなく,実数として除算されます.

以下のプログラムは,これらの複合演算子を使用して式を構築する方法を示しています:

basic-operators-and-functions-program2.cpp
#include <qbpp/qbpp.hpp>

int main() {
  auto x = qbpp::var("x");
  auto y = qbpp::var("y");
  auto f = 6 * x + 4;

  f += 3 * y;
  std::cout << "f = " << f << std::endl;

  f -= 12;
  std::cout << "f = " << f << std::endl;

  f *= 2 * y;
  std::cout << "f = " << f << std::endl;

  f /= 2;
  std::cout << "f = " << f << std::endl;
}

このプログラムの出力は次のとおりです:

f = 4 +6*x +3*y
f = -8 +6*x +3*y
f = -16*y +12*x*y +6*y*y
f = -8*y +6*x*y +3*y*y

二乗関数

Hi-QUBOは,式の二乗を計算するためのグローバル関数**qbpp::sqr()とqbpp::Exprクラスのメンバ関数sqr()**の両方を提供しています.

以下のプログラムでは,qbpp::Exprオブジェクトfに対して,グローバル関数**qbpp::sqr(f)はfの二乗を表す新しいqbpp::Exprオブジェクトを返し, 一方メンバ関数f.sqr()**はfをその場でその二乗に置き換えて更新します.

basic-operators-and-functions-program3.cpp
#include <qbpp/qbpp.hpp>

int main() {
  auto x = qbpp::var("x");
  auto f = x + 1;

  std::cout << "f = " << qbpp::sqr(f) << std::endl;
  std::cout << "f = " << f << std::endl;

  f.sqr();
  std::cout << "f = " << f << std::endl;
}

このプログラムの出力は次のとおりです:

f = 1 +x*x +2*x
f = 1 +x
f = 1 +x*x +2*x

簡約化関数

qbpp::Exprオブジェクトに演算子や関数が適用された後,式は自動的に展開されます. 項をソートし,結果の式を簡約化するには,簡約化関数を明示的に呼び出す必要があります.

Hi-QUBOは以下の3つのグローバル簡約化関数を提供しています:

  • qbpp::simplify(): 同一の項の係数をマージして簡約化された式を返します.

  • qbpp::simplify_as_binary(): すべての変数がバイナリ値\(0/1\)を取ることを仮定して簡約化された式を返します. すなわち,恒等式\(x^2=x\)が成り立つことを利用して,式を整理します.

  • qbpp::simplify_as_spin(): すべての変数がスピン値\(-1/+1\)を取ることを仮定して簡約化された式を返します. すなわち,恒等式\(x^2=1\)が成り立つことを利用して,式を整理します.

以下のプログラムは,これらの簡約化関数の動作を示しています:

basic-operators-and-functions-program4.cpp
#include <qbpp/qbpp.hpp>

int main() {
  auto x = qbpp::var("x");
  auto f = qbpp::sqr(x - 1);

  std::cout << "f = " << f << std::endl;
  std::cout << "simplified(f) = " << qbpp::simplify(f) << std::endl;
  std::cout << "simplified_as_binary(f) = " << qbpp::simplify_as_binary(f) << std::endl;
  std::cout << "simplified_as_spin(f) = " << qbpp::simplify_as_spin(f) << std::endl;
}

このプログラムの出力は次のとおりです:

f = 1 +x*x -2*x
simplified(f) = 1 -2*x +x*x
simplified_as_binary(f) = 1 -x
simplified_as_spin(f) = 2 -2*x

これらの簡約化関数のメンバ関数版もqbpp::Exprオブジェクトに対して提供されており,オブジェクトをその場で簡約化された結果に更新します.

例えば,以下のプログラムは**simplify()**を適用してfを更新します:

basic-operators-and-functions-program5.cpp
#include <qbpp/qbpp.hpp>

int main() {
  auto x = qbpp::var("x");
  auto f = qbpp::sqr(x - 1);

  f.simplify();
  std::cout << "f = " << f << std::endl;
}

このプログラムの出力は次のとおりです:

f = 1 -2*x +x*x

単項演算子と二項演算子

PyQBPPは,式を構築するための以下の基本的な二項演算子をサポートしています:

  • +: オペランドの和を返します.

  • -: オペランドの差を返します.

  • *: オペランドの積を返します.

  • /: オペランドの商を返します. 除数は整数でなければならず,被除数の定数項とすべての係数は除数で割り切れる必要があります.double フロントエンドのモジュール(pyqbpp.d など)では割り切れる必要はなく,係数はそのまま実数として除算されます.

  • 単項 -: オペランドの符号を反転した値を返します.

  • 単項 ~: 変数の否定リテラルを返します(バイナリ変数 x に対して,~x は \(1-x\) を表します).

+,-,*,/ の優先順位は標準的なPythonの演算子優先順位規則に従います.

以下のプログラムは,これらの演算子を使用して式を構築する方法を示しています:

basic-operators-and-functions-program1.py
import pyqbpp as qbpp

x = qbpp.var("x")
y = qbpp.var("y")
f = 6 * -(x + 1) * (y - 1)
g = f / 3

print("f =", f)
print("g =", g)

このプログラムの出力は以下の通りです:

f = 6 -6*y +6*x -6*x*y
g = 2 -2*y +2*x -2*x*y

注釈 PyQBPPでは +,-,*,/ のPython演算子が Var,Term,Expr クラス上でオーバーロードされています. +/- の結果は式(Expr)になり,* は Var・Term 同士では積の項(Term)を返します./(÷整数)は Term と Expr に対してのみ使用できます.

複合代入演算子

式を更新するための以下の複合代入演算子もサポートされています:

  • +=: 右辺のオペランドを左辺に加算します.

  • -=: 右辺のオペランドを左辺から減算します.

  • *=: 右辺のオペランドを左辺に乗算します.

  • /=: 左辺のオペランドを右辺で除算します.右辺のオペランドは整数でなければならず,左辺の定数項とすべての係数は割り切れる必要があります.double フロントエンドでは割り切れる必要はなく,実数として除算されます.

以下のプログラムは,これらの複合代入演算子を使用して式を更新する方法を示しています:

basic-operators-and-functions-program2.py
import pyqbpp as qbpp

x = qbpp.var("x")
y = qbpp.var("y")
f = 6 * x + 4

f += 3 * y
print("f =", f)

f -= 12
print("f =", f)

f *= 2 * y
print("f =", f)

f /= 2
print("f =", f)

このプログラムの出力は以下の通りです:

f = 4 +6*x +3*y
f = -8 +6*x +3*y
f = -16*y +12*x*y +6*y*y
f = -8*y +6*x*y +3*y*y

二乗関数

PyQBPPは,式の二乗を計算するためのグローバル関数 qbpp.sqr() と Expr クラスのメンバ関数 sqr() の両方を提供しています.

以下のプログラムでは,式 f に対して,グローバル関数 qbpp.sqr(f) は f を変更せずに f の二乗を表す新しい式を返します. 一方,メンバ関数 f.sqr() は f をその場でその二乗に置き換えて更新します.

basic-operators-and-functions-program3.py
import pyqbpp as qbpp

x = qbpp.var("x")
f = x + 1

print("f =", qbpp.sqr(f))
print("f =", f)

f.sqr()
print("f =", f)

このプログラムの出力は以下の通りです:

f = 1 +x*x +2*x
f = 1 +x
f = 1 +x*x +2*x

簡約化関数

式に演算子や関数が適用された後,式は自動的に展開されます. 項をソートし,結果の式を簡約化するには,簡約化関数を明示的に呼び出す必要があります.

PyQBPPは以下の3つのグローバル簡約化関数を提供しています:

  • qbpp.simplify(): 同一の項の係数をマージして簡約化された式を返します.

  • qbpp.simplify_as_binary(): すべての変数がバイナリ値 \(0/1\) を取ることを仮定して簡約化された式を返します. すなわち,恒等式 \(x^2=x\) が成り立つことを利用して,式を整理します.

  • qbpp.simplify_as_spin(): すべての変数がスピン値 \(-1/+1\) を取ることを仮定して簡約化された式を返します. すなわち,恒等式 \(x^2=1\) が成り立つことを利用して,式を整理します.

以下のプログラムは,これらの簡約化関数の動作を示しています:

basic-operators-and-functions-program4.py
import pyqbpp as qbpp

x = qbpp.var("x")
f = qbpp.sqr(x - 1)

print("f =", f)
print("simplified(f) =", qbpp.simplify(f))
print("simplified_as_binary(f) =", qbpp.simplify_as_binary(f))
print("simplified_as_spin(f) =", qbpp.simplify_as_spin(f))

このプログラムの出力は以下の通りです:

f = 1 +x*x -2*x
simplified(f) = 1 -2*x +x*x
simplified_as_binary(f) = 1 -x
simplified_as_spin(f) = 2 -2*x

これらの簡約化関数のメンバ関数版も式に対して提供されており,式をその場で簡約化された結果に更新します.

例えば,以下のプログラムは simplify() を適用して f を更新します:

basic-operators-and-functions-program5.py
import pyqbpp as qbpp

x = qbpp.var("x")
f = qbpp.sqr(x - 1)

f.simplify()
print("f =", f)

このプログラムの出力は以下の通りです:

f = 1 -2*x +x*x

注釈 PyQBPPでは,式(Expr)のメンバ関数(例: f.simplify(),f.sqr())はオブジェクトをその場で更新しますが,グローバル関数(例: qbpp.simplify(f),qbpp.sqr(f))は元のオブジェクトを変更せずに新しいオブジェクトを返します(式の配列のメンバ関数も同様にその場で更新します).