# 決定変数の作り方 Amplify SDK を使用して組合せ最適化問題を解くためには、問題の定式化をプログラムコード上で表現することが必要です。 このページでは、定式化の最初のステップとして、決定変数の生成について解説します。 ```{seealso} 変数を発行する方法としては、このページで解説する {py:class}`~amplify.VariableGenerator` クラスの {py:meth}`~amplify.VariableGenerator.scalar` および {py:meth}`~amplify.VariableGenerator.array` メソッドのほかに {py:meth}`~amplify.VariableGenerator.matrix` メソッドが提供されています。 二次の目的関数を係数行列形式で作成したい場合はこのメソッドを用いることができます。詳細は「[係数行列による目的関数の作成](matrix.md)」を参照してください。 ``` ## 変数ジェネレータの作成 組合せ最適化問題の定式化を行うには、最初に {py:class}`~amplify.VariableGenerator` クラスのインスタンスを作成することが必要です。このクラスは決定変数を発行するためのメソッドを提供します。 ```{testcode} from amplify import VariableGenerator gen = VariableGenerator() ``` ## 変数の生成 {py:class}`~amplify.VariableGenerator` クラスの {py:meth}`~amplify.VariableGenerator.scalar` メソッドを使うと、変数の種類を指定して新しい変数が発行できます。Amplify SDK で指定できる変数の種類は以下の表の通りです。 ```{list-table} :widths: auto :header-rows: 1 * - 変数種別 - 詳細 * - {py:class}`~amplify.VariableType.Binary` - 0 または 1 の値をとる変数 * - {py:class}`~amplify.VariableType.Ising` - -1 または 1 の値をとる変数 * - {py:class}`~amplify.VariableType.Integer` - 整数値をとる変数 * - {py:class}`~amplify.VariableType.Real` - 実数値をとる変数 ``` 次のようにして新しくバイナリ変数を発行します。 変数は変数の多項式を表す {py:class}`~amplify.Poly` クラスのインスタンスとして返されます。 ```{doctest} >>> q = gen.scalar("Binary") >>> print(q) q_0 ``` 発行される変数には自動で名前がつきますが、名前を指定することもできます。 ```{doctest} >>> i = gen.scalar("Ising", name="i") >>> print(i) i ``` 整数変数または実数変数には取り得る値の範囲を指定できます。 ```{doctest} >>> x = gen.scalar("Real", bounds=(2.0, 3.0)) >>> print(x) x_0 ``` ## 変数配列の作成 複数個の変数を一括で生成したい場合、{py:class}`~amplify.VariableGenerator` の {py:meth}`~amplify.VariableGenerator.array` メソッドを使うことができます。 このメソッドは、NumPy-like な多次元配列形式で変数の配列を返します。 次のようにして 3 個のバイナリ変数からなる配列を作成します。新たに 3 個の変数が発行され、変数名には自動で配列のインデックスを表す文字列が付きます。 ```{doctest} >>> gen = VariableGenerator() >>> q = gen.array("Binary", 3) >>> print(q) [q_0, q_1, q_2] ``` Python の {py:class}`list` や 1 次元 NumPy 配列と同様にして要素やスライスを取得することができます。 ```{doctest} >>> print(q[0]) q_0 ``` ```{doctest} >>> print(q[:2]) [q_0, q_1] ``` {py:class}`~amplify.VariableGenerator` の {py:meth}`~amplify.VariableGenerator.array` メソッドは多次元の配列も作成することができます。以下の例では、 {math}`2 \times 3` の 2 次元変数配列を作成します。 ```{doctest} >>> gen = VariableGenerator() >>> q = gen.array("Binary", shape=(2, 3)) >>> print(q) [[q_{0,0}, q_{0,1}, q_{0,2}], [q_{1,0}, q_{1,1}, q_{1,2}]] ``` 2 次元の {py:class}`numpy.ndarray` と同様にして要素やスライスを取得することができます。取得される要素やスライスは、もとの配列のビューとなります。 ```{doctest} >>> print(q[0, 0]) q_{0,0} ``` ```{doctest} >>> print(q[0, :]) [q_{0,0}, q_{0,1}, q_{0,2}] ``` ```{doctest} >>> print(q[:, 0]) [q_{0,0}, q_{1,0}] ``` 変数の下限値と上限値は発行時に一括で指定することができます。 ```{doctest} >>> n = gen.array("Integer", shape=(5,), bounds=(1, 3)) >>> print(n) [n_0, n_1, n_2, n_3, n_4] ``` ```{seealso} {py:meth}`~amplify.VariableGenerator.array` メソッドは多項式配列を表す {py:class}`~amplify.PolyArray` クラスのインスタンスを返します。 {py:class}`~amplify.PolyArray` クラスには要素の取得やスライス以外にも {py:class}`~numpy.ndarray` と互換性のあるさまざまなメソッドが提供されています。 詳細は{py:class}`~amplify.PolyArray` クラスの[リファレンス](amplify.PolyArray)を参照してください。 ``` (variable-info)= ## 変数情報の取得 発行した変数から変数の情報を取得するには、{py:meth}`~amplify.Poly.as_variable` メソッドを使います。 ```{testcode} gen = VariableGenerator() q = gen.scalar("Binary") i = gen.scalar("Ising", name="i") x = gen.scalar("Real", bounds=(2.0, 3.0)) ``` ```{doctest} >>> print(q.as_variable()) {name: q_0, id: 0, type: Binary} ``` 変数の情報は {py:class}`~amplify.Variable` クラスのインスタンスとして提供されます。{py:class}`~amplify.Variable` クラスの持つアトリビュートは以下の通りです。 ```{list-table} :width: 100% :header-rows: 1 * - アトリビュート - データ型 - 詳細 * - {py:attr}`~amplify.Variable.name` - {py:class}`str` - 変数名 * - {py:attr}`~amplify.Variable.id` - {py:class}`int` - 変数の識別番号 発行された順に0 から始まる整数値が割り当てられます * - {py:attr}`~amplify.Variable.type` - {py:class}`~amplify.VariableType` - 変数の種類 * - {py:attr}`~amplify.Variable.lower_bound` - {py:class}`float` - [整数変数または実数変数のみ] 変数の下限値 {py:obj}`None` は $- \inf$ を意味する * - {py:attr}`~amplify.Variable.upper_bound` - {py:class}`float` - [整数変数または実数変数のみ] 変数の上限値 {py:obj}`None` は $+ \inf$ を意味する ``` また、{py:class}`~amplify.VariableGenerator` クラスが発行した変数の情報は {py:attr}`~amplify.VariableGenerator.variables` プロパティで取得できます。 ```{doctest} >>> vars = gen.variables >>> vars # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS [Variable({name: q_0, id: 0, type: Binary}), Variable({name: i, id: 1, type: Ising}), Variable({name: x_0, id: 2, type: Real, lower_bound: 2, upper_bound: 3})] ``` 変数の名前、下限値、上限値については後から変更することも可能です。 ```{testcode} vars[2].name = "r" vars[2].lower_bound = 0.0 vars[2].upper_bound = 1.0 ``` ```{doctest} >>> print(vars[2]) {name: r, id: 2, type: Real, lower_bound: 0, upper_bound: 1} ``` ````{attention} {py:meth}`~amplify.VariableGenerator.scalar` メソッドなどにより発行される変数は {py:class}`~amplify.Poly` クラスのインスタンスです。 {py:class}`~amplify.Poly` クラスは単一の変数だけでなく一般の多項式も表現できますが、{py:meth}`~amplify.Poly.as_variable` メソッドは {py:class}`~amplify.Poly` クラスのインスタンスが単項の変数を表すときのみ成功することに注意してください。 ```` ````{tip} 簡便のために、{py:meth}`~amplify.Poly.is_variable` メソッドが {py:obj}`True` を返す場合 ({py:meth}`~amplify.Poly.as_variable` メソッドが成功する場合) は、{py:class}`~amplify.Variable` クラスのアトリビュートに直接アクセスできます。 ```{doctest} >>> q.is_variable() True >>> q.name 'q_0' >>> q.id 0 >>> print(q.type) Binary ``` ```` ````{tip} 任意の {py:class}`~amplify.Poly` クラスのインスタンスに対して、そのインスタンスに含まれるすべての変数の情報を {py:attr}`~amplify.Poly.variables` プロパティにより取得することができます。{py:class}`~amplify.Poly` クラスの詳細は「[多項式と目的関数](objective.md)」を参照してください。 ```{doctest} >>> q.variables [Variable({name: q_0, id: 0, type: Binary})] ``` ````