Quick Reference: Operators and Functions for Expressions
The table below summarizes the operators and functions available for qbpp::Expr objects.
| Operators/Functions | Operator Symbols/Function Names | Function Type | Return Type | Argument Type |
|---|---|---|---|---|
| Type Conversion | toExpr() | Global | qbpp::Expr | ExprType |
| Assignment | = | Member | qbpp::Expr | ExprType |
| Binary Operators | +, -, * | Global | qbpp::Expr | ExprType-ExprType |
| Compound Assignment Operators | +=, -=, *= | Member | qbpp::Expr | ExprType |
| Division | / | Global | qbpp::Expr | ExprType-Int |
| Compound Division | /= | Member | qbpp::Expr | Int |
| Unary Operators | +, - | Global | qbpp::Expr | ExprType |
| Comparison (Equality) | == | Global | qbpp::ExprExpr | ExprType-Int |
| Comparison (Range Comparison) | <= <= | Global | qbpp::ExprExpr | IntInf-ExprType-IntInf |
| Square | sqr() | Global | qbpp::Expr | ExprType |
| Square | sqr() | Member | qbpp::Expr | - |
| GCD | gcd() | Global | Int | ExprType |
| Simplify | simplify(), simplify_as_binary(), simplify_as_spin() | Global | qbpp::Expr | ExprType |
| Simplify | simplify(), simplify_as_binary(), simplify_as_spin() | Member | qbpp::Expr | - |
| Eval | operator() | Member | Int | ExprType-qbpp::MapList |
| Replace | replace() | Global | qbpp::Expr | ExprType-qbpp::MapList |
| Replace | replace() | Member | qbpp::Expr | qbpp::MapList |
| Binary/Spin Conversion | binary_to_spin(), spin_to_binary() | Global | qbpp::Expr | ExprType |
| Binary/Spin Conversion | binary_to_spin(), spin_to_binary() | Member | qbpp::Expr | - |
| Range Slice | slice(), head(), tail() | Global | Array | Array |
| Axis-fixing Slice | row(), col(), slice() | Global | Array | Array |
| Concatenation | concat() | Global | Array | Array-Array |
| Concatenation (with scalar) | concat() | Global | Array | Expr-Array |
Type Conversion: qbpp::toExpr()
The global function qbpp::toExpr() converts its argument into a qbpp::Expr instance and returns it. The argument may be:
- an integer
- a variable (
qbpp::Var) - a product term (
qbpp::Term) - an expression (
qbpp::Expr) — in this case, no conversion is performed
We refer to these argument types collectively as ExprType.
Expression-related type: ExprType
The term ExprType denotes a category of types that can be converted to a qbpp::Expr object.
Integer-Related Types: Int and IntInf
Int: ordinary integersIntInf: either an integer,-qbpp::inf, or+qbpp::inf, representing infinite bounds.
Global and Member Functions
Operators and functions related to qbpp::Expr are provided in two forms:
- Global functions: These take at least one ExprType argument and typically return a new
qbpp::Exprobject without modifying the inputs. - Member functions: These are member functions of the
qbpp::Exprclass. In many cases, they update the calling object and also return the resultingqbpp::Expr.
Example: sqr()
The sqr() function computes the square of an expression and is available in both forms:
sqr(f)(global): returns the square of f without modifying ff.sqr()(member): updates f to its square and returns the updated expression
Assignment Operator: =
The left-hand side must be a qbpp::Expr object. The right-hand side must be an ExprType, which is first converted to a qbpp::Expr. The converted expression is then assigned to the left-hand side.
Binary Operators: +, -, *
These operators are defined as global functions. They take two ExprType operands, compute the result, and return it. If at least one operand is a qbpp::Expr, the result is always a qbpp::Expr. If neither operand is a qbpp::Expr, the result may be a qbpp::Term.
Example
For a variable x of type qbpp::Var:
2 + x:qbpp::Expr2 * x:qbpp::Term
Compound Assignment Operators: +=, -=, *=
These operators are defined as member functions. The left-hand side must be a qbpp::Expr. The specified operation is applied using the right-hand side operand. The left-hand side expression is updated in place.
Division / and Compound Division /=
The division operator / is defined as a global function.
It takes a non-integer ExprType operand as the dividend and an integer operand as the divisor, and returns the quotient as a qbpp::Expr.
The dividend expression must be divisible by the divisor; that is, both the integer constant term and all integer coefficients in the expression must be divisible by the divisor.
The compound division operator /= is defined as a member function.
- The left-hand side must be a
qbpp::Expr. - The right-hand side must be an integer.
The same divisibility condition applies, and the division is performed in place, updating the left-hand side expression.
Comparison (Equality): ==
The equality comparison operator == takes:
- a non-integer
ExprTypeon the left-hand side, and - an integer on the right-hand side.
It returns an expression whose minimum value is 0 when the equality constraint is satisfied. More specifically, for a non-integer ExprType object f and an integer n, the operator returns: qbpp::sqr(f-n).
For the returned object g:
grepresents the constraint expressionqbpp::sqr(f - n), and*greturns the underlying expressionf.
qbpp::ExprExpr class
Here, g is a qbpp::ExprExpr object, which is a derived class of qbpp::Expr. Dereferencing g using the * operator returns the associated underlying qbpp::Expr object.
Comparison (Range Comparison): <= <=
The range comparison operator is written in the form:
l <= f <= u
where:
fis a non-integer ExprType, andlanduare integers.
This operator returns an expression whose minimum value is 0 when the range constraint is satisfied.
More specifically, an auxiliary integer variable a with unit gaps, taking values in the range [l,u−1], is implicitly introduced, and the operator returns:
(f - a)(f - (a + 1))
For the returned qbpp::ExprExpr object g:
grepresents the constraint expression(f - a)(f - (a + 1)), and*greturns the underlying expressionf.
Square functions: sqr()
For a qbpp::Expr object f:
qbpp::sqr(f)(global function): Returns the expressionf * f. The argumentfmay be a non-integerExprTypeobject.f.sqr()(member function): Updatesfin place by replacing it withf * f, and returns the updated expression.
Greatest Common Divisor function gcd()
The global function gcd() takes a qbpp::Expr object as its argument and returns the greatest common divisor (GCD) of all integer coefficients and the integer constant term.
Since the given qbpp::Expr object is divisible by the resulting GCD, all integer coefficients and the integer constant term can be reduced by dividing by the GCD without changing the structure of the expression or its optimal solutions.
Simplify functions: simplify(), simplify_as_binary(), simplify_as_spin()
For a qbpp::Expr object f, the member function f.simplify() performs the following operations in place:
- Sort variables within each term according to their unique variable IDs
- Merge duplicated terms
- Sort terms such that:
- lower-degree terms appear earlier, and
- terms of the same degree are ordered lexicographically.
The global function qbpp::simplify(f) performs the same operations without modifying f.
Binary and Spin Simplification
Two specialized variants of the simplification function are provided:
simplify_as_binary(): Simplification is performed under the assumption that all variables take binary values $\lbrace 0,1\rbrace$. The identity $x^2=x$ is applied to all variables $x$.simplify_as_spin()Simplification is performed under the assumption that all variables take spin values $\lbrace -1,+1\rbrace$. The identity $x^2=1$ is applied to all variables $x$.
Both variants are available as member functions and global functions:
- Member functions: These perform simplification in place and update
f.f.simplify_as_binary()f.simplify_as_spin()
- Global functions: These return a simplified expression without modifying f.
qbpp::simplify_as_binary(f)qbpp::simplify_as_spin(f)
Evaluation function
A qbpp::MapList object stores a list of pairs consisting of a qbpp::Var object and an integer. Each pair defines a mapping from a variable to an integer value.
For a qbpp::Expr object f and a qbpp::MapList object ml, the evaluation function f(ml) evaluates the value of f under the variable assignments specified by ml and returns the resulting integer value.
All variables appearing in f must have corresponding mappings defined in ml.
Replace Functions: replace()
A qbpp::MapList object may also contain pairs consisting of a qbpp::Var object and an ExprType object. Such pairs define mappings from variables to expressions.
For a qbpp::Expr object f and a qbpp::MapList object ml:
qbpp::replace(f, ml): Returns a newqbpp::Exprobject obtained by replacing variables infaccording to the mappings inml, without modifyingf.f.replace(ml): Replaces variables infaccording to the mappings inmlin place and returns the resultingqbpp::Exprobject.
Binary/Spin Conversion functions: spin_to_binary(), binary_to_spin()
Let x be a binary variable and s be a spin variable. We assume that x = 1 if and only if s = 1. Under this assumption, the following relations hold:
Let $f(s)$ be a function of a spin variable $s$. Then the function $g(x)=f(2x−1)$ is a function of the binary variable $x$ that yields the same value under the above relation.
The spin_to_binary() function uses this relation to convert a qbpp::Expr object representing a function of spin variables into an equivalent qbpp::Expr object representing a function of binary variables. More specifically, it replaces all spin variables s in f by 2 * s - 1.
qbpp::spin_to_binary(f): Produces and returns a newqbpp::Exprobject by replacing all spin variablessinfwith2 * s - 1.f.spin_to_binary(): Updatesfin place usingqbpp::spin_to_binary(f)and returns the updated expression.
Similarly, the binary_to_spin() function replaces all binary variables x in f by (x + 1) / 2. The resulting expression may contain non-integer coefficients. Therefore, the entire expression is multiplied by $2^d$ where $d$ is the maximum degree of all terms, so that all coefficients become integers.
As with spin_to_binary(), both global and member function variants of binary_to_spin() are provided.
Slice Functions: slice(), head(), tail(), row(), col()
The slice functions extract sub-arrays from a qbpp::Array.
Range Slice: slice(), head(), tail()
Extract a contiguous sub-range along a dimension.
Member functions (in-place, modify the array):
v.slice(dim, from, to): Keeps elements in the range[from, to)along dimensiondim.v.head(n): Keeps the firstnelements.v.tail(n): Keeps the lastnelements.
Global functions (non-destructive, return a new array):
qbpp::slice(v, dim, from, to)qbpp::head(v, n),qbpp::head(v, n, dim)qbpp::tail(v, n),qbpp::tail(v, n, dim)
Axis-fixing Slice: row(), col(), slice()
Extract a sub-array by fixing specific axes at given indices.
Member functions (in-place):
v.row(i): Fix axis 0 at indexi.v.col(j): Fix axis 1 at indexj.v.slice({{axis, index}, ...}): Fix multiple axes simultaneously.
Global functions (non-destructive):
qbpp::row(v, i)qbpp::col(v, j)qbpp::slice(v, {{axis, index}, ...})
Example: Adjacent Difference
auto x = qbpp::var("x", 5);
auto diff = qbpp::head(x, 4) - qbpp::tail(x, 4);
// diff = {x[0]-x[1], x[1]-x[2], x[2]-x[3], x[3]-x[4]}
Example: Row Operations
auto x = qbpp::var("x", 3, 4);
auto prod = qbpp::row(x, 0) * qbpp::row(x, 1); // element-wise product of rows
auto s = qbpp::sum(prod);
For more details and examples, see Slice and Concat Functions.
Concat Functions: concat()
The concat functions join arrays or append/prepend scalars.
Array + Array
qbpp::concat(a, b): Concatenates two arrays of the same type along the outermost dimension.
Scalar + Array / Array + Scalar
qbpp::concat(scalar, v): Prepends a scalar to an array. ReturnsArray.qbpp::concat(v, scalar): Appends a scalar to an array. ReturnsArray.
The scalar is implicitly converted to qbpp::Expr.
2D Concat with Dimension
qbpp::concat(a, b, dim): Concatenates two 2D arrays along the specified dimension.dim=0: row concatenation (appends rows)dim=1: column concatenation (appends columns; both must have the same number of rows)
Example: Boundary Difference
auto x = qbpp::var("x", 4);
auto diff = qbpp::concat(1, x) - qbpp::concat(x, 0);
// diff = {1-x[0], x[0]-x[1], x[1]-x[2], x[2]-x[3], x[3]-0}
クイックリファレンス: 式の演算子と関数
以下の表は、qbpp::Exprオブジェクトで利用可能な演算子と関数をまとめたものです。
| 演算子/関数 | 演算子記号/関数名 | 関数タイプ | 戻り値の型 | 引数の型 |
|---|---|---|---|---|
| 型変換 | toExpr() | グローバル | qbpp::Expr | ExprType |
| 代入 | = | メンバ | qbpp::Expr | ExprType |
| 二項演算子 | +, -, * | グローバル | qbpp::Expr | ExprType-ExprType |
| 複合代入演算子 | +=, -=, *= | メンバ | qbpp::Expr | ExprType |
| 除算 | / | グローバル | qbpp::Expr | ExprType-Int |
| 複合除算 | /= | メンバ | qbpp::Expr | Int |
| 単項演算子 | +, - | グローバル | qbpp::Expr | ExprType |
| 比較(等値) | == | グローバル | qbpp::ExprExpr | ExprType-Int |
| 比較(範囲比較) | <= <= | グローバル | qbpp::ExprExpr | IntInf-ExprType-IntInf |
| 二乗 | sqr() | グローバル | qbpp::Expr | ExprType |
| 二乗 | sqr() | メンバ | qbpp::Expr | - |
| 最大公約数 | gcd() | グローバル | Int | ExprType |
| 簡約化 | simplify(), simplify_as_binary(), simplify_as_spin() | グローバル | qbpp::Expr | ExprType |
| 簡約化 | simplify(), simplify_as_binary(), simplify_as_spin() | メンバ | qbpp::Expr | - |
| 評価 | operator() | メンバ | Int | ExprType-qbpp::MapList |
| 置換 | replace() | グローバル | qbpp::Expr | ExprType-qbpp::MapList |
| 置換 | replace() | メンバ | qbpp::Expr | qbpp::MapList |
| バイナリ/スピン変換 | binary_to_spin(), spin_to_binary() | グローバル | qbpp::Expr | ExprType |
| バイナリ/スピン変換 | binary_to_spin(), spin_to_binary() | メンバ | qbpp::Expr | - |
| 範囲スライス | slice(), head(), tail() | グローバル | Array | Array |
| 軸固定スライス | row(), col(), slice() | グローバル | Array | Array |
| 連結 | concat() | グローバル | Array | Array-Array |
| 連結(スカラー付き) | concat() | グローバル | Array | Expr-Array |
型変換: qbpp::toExpr()
グローバル関数qbpp::toExpr()は引数をqbpp::Exprインスタンスに変換して返します。 引数は以下のいずれかです:
- 整数
- 変数(
qbpp::Var) - 積項(
qbpp::Term) - 式(
qbpp::Expr)– この場合、変換は行われません
これらの引数の型を総称してExprTypeと呼びます。
式関連の型: ExprType
ExprTypeという用語は、qbpp::Exprオブジェクトに変換可能な型のカテゴリを示します。
整数関連の型: IntとIntInf
Int: 通常の整数IntInf: 整数、-qbpp::inf、または+qbpp::infのいずれかで、無限の境界を表します。
グローバル関数とメンバ関数
qbpp::Exprに関連する演算子と関数は2つの形式で提供されます:
- グローバル関数: 少なくとも1つのExprType引数を取り、通常は入力を変更せずに新しい
qbpp::Exprオブジェクトを返します。 - メンバ関数:
qbpp::Exprクラスのメンバ関数です。 多くの場合、呼び出し元のオブジェクトを更新し、結果のqbpp::Exprも返します。
例: sqr()
sqr()関数は式の二乗を計算し、両方の形式で利用できます:
sqr(f)(グローバル): fを変更せずにfの二乗を返しますf.sqr()(メンバ): fをその二乗に更新し、更新された式を返します
代入演算子: =
左辺はqbpp::Exprオブジェクトでなければなりません。 右辺はExprTypeでなければならず、まずqbpp::Exprに変換されます。 変換された式が左辺に代入されます。
二項演算子: +, -, *
これらの演算子はグローバル関数として定義されています。 2つのExprTypeオペランドを取り、結果を計算して返します。 少なくとも1つのオペランドがqbpp::Exprの場合、結果は常にqbpp::Exprになります。 どちらのオペランドもqbpp::Exprでない場合、結果はqbpp::Termになることがあります。
例
qbpp::Var型の変数xの場合:
2 + x:qbpp::Expr2 * x:qbpp::Term
複合代入演算子: +=, -=, *=
これらの演算子はメンバ関数として定義されています。 左辺はqbpp::Exprでなければなりません。 右辺のオペランドを使用して指定された演算が適用されます。 左辺の式がその場で更新されます。
除算/と複合除算/=
除算演算子/はグローバル関数として定義されています。
非整数のExprTypeオペランドを被除数として、整数オペランドを除数として取り、商をqbpp::Exprとして返します。
被除数の式は除数で割り切れなければなりません。つまり、 式内の整数定数項とすべての整数係数が除数で割り切れる必要があります。
複合除算演算子/=はメンバ関数として定義されています。
- 左辺は
qbpp::Exprでなければなりません。 - 右辺は整数でなければなりません。
同じ割り切れ条件が適用され、除算はその場で実行され、左辺の式が更新されます。
比較(等値): ==
等値比較演算子==は以下を取ります:
- 左辺に非整数の
ExprType - 右辺に整数
等値制約が満たされたときに最小値0となる式を返します。 より具体的には、非整数のExprTypeオブジェクトfと整数nに対して、演算子はqbpp::sqr(f-n)を返します。
返されたオブジェクトgについて:
gは制約式qbpp::sqr(f - n)を表し、*gは基礎となる式fを返します。
qbpp::ExprExprクラス
ここでgはqbpp::ExprExprオブジェクトであり、qbpp::Exprの派生クラスです。 *演算子を使用してgを間接参照すると、関連付けられた基礎となるqbpp::Exprオブジェクトが返されます。
比較(範囲比較): <= <=
範囲比較演算子は次の形式で記述されます:
l <= f <= u
ここで:
fは非整数のExprType、lとuは整数です。
この演算子は、範囲制約が満たされたときに最小値0となる式を返します。
より具体的には、単位間隔を持つ補助整数変数aが範囲[l,u-1]の値を取るように暗黙的に導入され、演算子は以下を返します:
(f - a)(f - (a + 1))
返されたqbpp::ExprExprオブジェクトgについて:
gは制約式(f - a)(f - (a + 1))を表し、*gは基礎となる式fを返します。
二乗関数: sqr()
qbpp::Exprオブジェクトfに対して:
qbpp::sqr(f)(グローバル関数): 式f * fを返します。 引数fは非整数のExprTypeオブジェクトでもかまいません。f.sqr()(メンバ関数):fをその場でf * fに置き換え、更新された式を返します。
最大公約数関数gcd()
グローバル関数gcd()はqbpp::Exprオブジェクトを引数として取り、すべての整数係数と整数定数項の最大公約数(GCD)を返します。
与えられたqbpp::Exprオブジェクトは結果のGCDで割り切れるため、すべての整数係数と整数定数項をGCDで除算しても、式の構造や最適解は変わりません。
簡約化関数: simplify(), simplify_as_binary(), simplify_as_spin()
qbpp::Exprオブジェクトfに対して、メンバ関数f.simplify()は以下の操作をその場で実行します:
- 各項内の変数を一意な変数IDに従ってソート
- 重複する項をマージ
- 項を以下の規則でソート:
- 低次の項が先に現れる
- 同じ次数の項は辞書順に並べる
グローバル関数qbpp::simplify(f)はfを変更せずに同じ操作を実行します。
バイナリとスピンの簡約化
簡約化関数の2つの特殊なバリアントが提供されています:
simplify_as_binary(): すべての変数がバイナリ値$\lbrace 0,1\rbrace$を取ることを仮定して簡約化が実行されます。 恒等式$x^2=x$がすべての変数$x$に適用されます。simplify_as_spin()すべての変数がスピン値$\lbrace -1,+1\rbrace$を取ることを仮定して簡約化が実行されます。 恒等式$x^2=1$がすべての変数$x$に適用されます。
両方のバリアントはメンバ関数とグローバル関数として利用できます:
- メンバ関数: その場で簡約化を実行し、
fを更新します。f.simplify_as_binary()f.simplify_as_spin()
- グローバル関数: fを変更せずに簡約化された式を返します。
qbpp::simplify_as_binary(f)qbpp::simplify_as_spin(f)
評価関数
qbpp::MapListオブジェクトは、qbpp::Varオブジェクトと整数のペアのリストを格納します。 各ペアは変数から整数値へのマッピングを定義します。
qbpp::Exprオブジェクトfとqbpp::MapListオブジェクトmlに対して、評価関数f(ml)はmlで指定された変数割り当ての下でfの値を評価し、結果の整数値を返します。
fに現れるすべての変数は、mlに対応するマッピングが定義されていなければなりません。
置換関数: replace()
qbpp::MapListオブジェクトには、qbpp::VarオブジェクトとExprTypeオブジェクトのペアも含めることができます。 このようなペアは変数から式へのマッピングを定義します。
qbpp::Exprオブジェクトfとqbpp::MapListオブジェクトmlに対して:
qbpp::replace(f, ml):fを変更せずに、mlのマッピングに従ってf内の変数を置換した新しいqbpp::Exprオブジェクトを返します。f.replace(ml):mlのマッピングに従ってf内の変数をその場で置換し、結果のqbpp::Exprオブジェクトを返します。
バイナリ/スピン変換関数: spin_to_binary(), binary_to_spin()
xをバイナリ変数、sをスピン変数とします。 x = 1であるとき、かつそのときに限りs = 1であると仮定します。 この仮定の下で、以下の関係が成り立ちます:
$f(s)$をスピン変数$s$の関数とします。 このとき、関数$g(x)=f(2x-1)$は上記の関係の下で同じ値を与えるバイナリ変数$x$の関数です。
spin_to_binary()関数はこの関係を使用して、スピン変数の関数を表すqbpp::Exprオブジェクトをバイナリ変数の関数を表す等価なqbpp::Exprオブジェクトに変換します。 具体的には、f内のすべてのスピン変数sを2 * s - 1に置換します。
qbpp::spin_to_binary(f):f内のすべてのスピン変数sを2 * s - 1に置換した新しいqbpp::Exprオブジェクトを生成して返します。f.spin_to_binary():qbpp::spin_to_binary(f)を使用してfをその場で更新し、更新された式を返します。
同様に、binary_to_spin()関数はf内のすべてのバイナリ変数xを(x + 1) / 2に置換します。 結果の式には非整数の係数が含まれる場合があります。 そのため、すべての係数が整数になるように、式全体が$2^d$($d$はすべての項の最大次数)で乗算されます。
spin_to_binary()と同様に、binary_to_spin()にもグローバル関数とメンバ関数の両方のバリアントが提供されています。
スライス関数: slice(), head(), tail(), row(), col()
スライス関数は qbpp::Array からサブ配列を取り出します。
範囲スライス: slice(), head(), tail()
次元に沿った連続する部分範囲を取り出します。
メンバ関数(in-place、配列を更新):
v.slice(dim, from, to): 次元dimの[from, to)の範囲の要素を残します。v.head(n): 先頭のn個の要素を残します。v.tail(n): 末尾のn個の要素を残します。
グローバル関数(非破壊、新しい配列を返す):
qbpp::slice(v, dim, from, to)qbpp::head(v, n)、qbpp::head(v, n, dim)qbpp::tail(v, n)、qbpp::tail(v, n, dim)
軸固定スライス: row(), col(), slice()
特定の軸をインデックスで固定してサブ配列を取り出します。
メンバ関数(in-place):
v.row(i): axis 0 をインデックスiに固定。v.col(j): axis 1 をインデックスjに固定。v.slice({{axis, index}, ...}): 複数の軸を同時に固定。
グローバル関数(非破壊):
qbpp::row(v, i)qbpp::col(v, j)qbpp::slice(v, {{axis, index}, ...})
例: 隣接差分
auto x = qbpp::var("x", 5);
auto diff = qbpp::head(x, 4) - qbpp::tail(x, 4);
// diff = {x[0]-x[1], x[1]-x[2], x[2]-x[3], x[3]-x[4]}
例: 行演算
auto x = qbpp::var("x", 3, 4);
auto prod = qbpp::row(x, 0) * qbpp::row(x, 1); // 行同士の要素毎積
auto s = qbpp::sum(prod);
詳細と例については スライス関数と連結関数 を参照してください。
連結関数: concat()
連結関数は配列の結合やスカラーの追加・先頭追加を行います。
配列 + 配列
qbpp::concat(a, b): 同じ型の2つの配列を最外次元に沿って連結します。
スカラー + 配列 / 配列 + スカラー
qbpp::concat(scalar, v): 配列の先頭にスカラーを追加します。qbpp::concat(v, scalar): 配列の末尾にスカラーを追加します。
スカラーはqbpp::Exprに暗黙的に変換されます。
2次元の次元指定付き連結
qbpp::concat(a, b, dim): 2つの2次元配列を指定した次元に沿って連結します。dim=0: 行方向の連結(行を追加)dim=1: 列方向の連結(列を追加。両方の行数が同じである必要があります)
例: 境界差分
auto x = qbpp::var("x", 4);
auto diff = qbpp::concat(1, x) - qbpp::concat(x, 0);
// diff = {1-x[0], x[0]-x[1], x[1]-x[2], x[2]-x[3], x[3]-0}