# Creating Decision Variables You must express the problem formulation in the program code to solve a combinatorial optimization problem with Amplify SDK. This page describes the first step in the formulation: generating the decision variables. ```{seealso} To issue decision variables, you can also use the {py:meth}`~amplify.VariableGenerator.matrix` method, as well as the methods described on this page, {py:meth}`~amplify.VariableGenerator.scalar` and {py:meth}`~amplify.VariableGenerator.array` of the {py:class}`~amplify.VariableGenerator` class. You can use the {py:meth}`~amplify.VariableGenerator.matrix` method to create a quadratic objective function in a coefficient matrix format. See "[Objective function with a coefficient matrix](matrix.md)" for details. ``` ## Creating a variable generator To formulate a combinatorial optimization problem, it is first necessary to create an instance of the {py:class}`~amplify.VariableGenerator` class. This class provides methods for issuing decision variables. ```{testcode} from amplify import VariableGenerator gen = VariableGenerator() ``` ## Variable generation You can use the {py:meth}`~amplify.VariableGenerator.scalar` method of the {py:class}`~amplify.VariableGenerator` class to issue a new decision variable by specifying the variable type. ```{list-table} :widths: auto :header-rows: 1 * - Variable type - Description * - {py:class}`~amplify.VariableType.Binary` - A variable taking the value 0 or 1 * - {py:class}`~amplify.VariableType.Ising` - A variable taking the value -1 or 1 * - {py:class}`~amplify.VariableType.Integer` - A variable taking an integer value * - {py:class}`~amplify.VariableType.Real` - A variable taking a real value ``` Following is an example of issuing a new binary variable. The variable is returned as an instance of the {py:class}`~amplify.Poly` class, which represents the polynomial of the variable. ```{doctest} >>> q = gen.scalar("Binary") >>> print(q) q_0 ``` Issued variables are automatically named, but you can also specify a name. ```{doctest} >>> i = gen.scalar("Ising", name="i") >>> print(i) i ``` Integer or real variables can have a range of possible values. ```{doctest} >>> x = gen.scalar("Real", bounds=(2.0, 3.0)) >>> print(x) x_0 ``` ## Creating an array of variables If you want to create multiple variables at once, you can use the {py:meth}`~amplify.VariableGenerator.array` method of the {py:class}`~amplify.VariableGenerator` class. This method returns an array of variables in a NumPy-like multidimensional array format. You can create an array of 3 binary variables as follows. Once the new variables are created, the variable names are automatically added with a string representing the array index. ```{doctest} >>> gen = VariableGenerator() >>> q = gen.array("Binary", 3) >>> print(q) [q_0, q_1, q_2] ``` You can retrieve the elements and slices like a Python {py:class}`list` or 1D NumPy array. ```{doctest} >>> print(q[0]) q_0 ``` ```{doctest} >>> print(q[:2]) [q_0, q_1] ``` The {py:meth}`~amplify.VariableGenerator.array` method of the {py:class}`~amplify.VariableGenerator` class can also create multidimensional arrays. The following example creates a two-dimensional {math}`2 \times 3` variable array. ```{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}]] ``` You can retrieve elements and slices in the same way as for a two-dimensional {py:class}`numpy.ndarray`. The retrieved element or slice will be the view of the original array. ```{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}] ``` You can specify the lower and upper bounds for variables simultaneously at output time. ```{doctest} >>> n = gen.array("Integer", shape=(5,), bounds=(1, 3)) >>> print(n) [n_0, n_1, n_2, n_3, n_4] ``` ```{seealso} The {py:meth}`~amplify.VariableGenerator.array` method returns an instance of the {py:class}`~amplify.PolyArray` class, representing a polynomial array. The {py:class}`~amplify.PolyArray` class provides a variety of methods compatible with {py:class}`~numpy.ndarray`, as well as element retrieval and slicing. See the {py:class}`~amplify.PolyArray` class [reference](amplify.PolyArray) for details. ``` (variable-info)= ## Getting variable information To get variable information from a given variable, use the {py:meth}`~amplify.Poly.as_variable` method. ```{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} ``` The Amplify SDK provides variable information as an instance of the {py:class}`~amplify.Variable` class, which has the following attributes. ```{list-table} :width: 100% :header-rows: 1 * - Attribute - Data type - Details * - {py:attr}`~amplify.Variable.name` - {py:class}`str` - Variable name * - {py:attr}`~amplify.Variable.id` - {py:class}`int` - Variable ID number An integer value assigned starting from 0 in order of issuance * - {py:attr}`~amplify.Variable.type` - {py:class}`~amplify.VariableType` - Variable type * - {py:attr}`~amplify.Variable.lower_bound` - {py:class}`float` - [Integer or real variable only] Variable lower bound {py:obj}`None` means $- \inf$. * - {py:attr}`~amplify.Variable.upper_bound` - {py:class}`float` - [Integer or real variable only] Variable upper bound {py:obj}`None` means $+ \inf$. ``` In addition, information about variables issued by the {py:class}`~amplify.VariableGenerator` class can be obtained using the {py:attr}`~amplify.VariableGenerator.variables` property. ```{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})] ``` You can change the variable's name and lower and upper bounds later. ```{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} The variables returned by the methods such as the {py:meth}`~amplify.VariableGenerator.scalar` method are instances of the {py:class}`~amplify.Poly` class. Note that the {py:class}`~amplify.Poly` class can represent not only single variables but also general polynomials. However, the {py:meth}`~amplify.Poly.as_variable` method will only succeed if the {py:class}`~amplify.Poly` class instance represents a unary variable. ```` ````{tip} For convenience, when the {py:meth}`~amplify.Poly.is_variable` method returns {py:obj}`True` ({py:meth}`~amplify.Poly.as_variable` method succeeds), you can access the attributes of the {py:class}`~amplify.Variable` class directly. ```{doctest} >>> q.is_variable() True >>> q.name 'q_0' >>> q.id 0 >>> print(q.type) Binary ``` ```` ````{tip} For each instance of the {py:class}`~amplify.Poly` class, you can retrieve information about all of the variables contained in that instance with the {py:attr}`~amplify.Poly.variables` property; see "[](objective.md)" for details about the {py:class}`~amplify.Poly` class. ```{doctest} >>> q.variables [Variable({name: q_0, id: 0, type: Binary})] ``` ````