# Model Formulation A combinatorial optimization problem comprises decision variables, objective functions, and constraints. In "2. [](variables.md)," "3. [](objective.md)," and "4. [](constraint.md)," we explained that you can create decision variables using {py:class}`~amplify.VariableGenerator`. At the same time, you can construct objective functions and constraints using {py:class}`~amplify.Poly` and {py:class}`~amplify.Constraint`. This page describes how these can be combined and used together to express combinatorial optimization problems in program code. ```{seealso} In addition to the {py:class}`~amplify.Poly` class, you can use instances of the coefficient matrix {py:class}`~amplify.Matrix` class as an objective function. When you construct the objective function as {py:class}`~amplify.Matrix`, you can use it in the same way described on this page. For details on the format of the coefficient matrix, see "[](matrix.md)". ``` ## Model construction The Amplify SDK represents combinatorial optimization problems as instances of the {py:class}`~amplify.Model` class. For a combinatorial optimization problem with an objective function and constraints, a simple way is to add a {py:class}`~amplify.Poly` representing the objective function and a {py:class}`~amplify.Constraint` or {py:class}`~amplify.ConstraintList` defining the constraints. ```{testcode} from amplify import VariableGenerator, Model, equal_to, one_hot gen = VariableGenerator() q = gen.array("Binary", shape=(2, 3)) objective = q[0, 0] * q[0, 1] - q[0, 2] constraint1 = equal_to(q[0, 0] + q[0, 1] - q[0, 2], 0) constraint2 = one_hot(q[1, :]) constraint_list = constraint1 + constraint2 ``` * Constructing the model by adding the objective function and constraints: ```{doctest} >>> model = objective + constraint1 >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1) ``` * Constructing the model by adding the objective function and the constraint list: ```{doctest} >>> model = objective + constraint_list >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1), q_{1,0} + q_{1,1} + q_{1,2} == 1 (weight: 1) ``` For a combinatorial optimization problem consisting of either an objective function or constraints, you can pass a {py:class}`~amplify.Poly` (or {py:class}`~amplify.Matrix`) instance to the constructor of the {py:class}`~amplify.Model` class to represent the objective function or a {py:class}`~amplify.Constraint` or {py:class}`~amplify.ConstraintList` instance to represent the constraints. * Constructing a model from the objective function ({py:class}`~amplify.Poly`): ```{doctest} >>> model = Model(objective) >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} ``` * Constructing a model from a single constraint object ({py:class}`~amplify.Constraint`): ```{doctest} >>> model = Model(constraint1) >>> print(model) minimize: 0 subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1) ``` * Constructing a model from multiple constraint objects ({py:class}`~amplify.ConstraintList`): ```{doctest} >>> model = Model(constraint_list) >>> print(model) minimize: 0 subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1), q_{1,0} + q_{1,1} + q_{1,2} == 1 (weight: 1) ``` You can also add constraints ({py:class}`~amplify.Constraint` or {py:class}`~amplify.ConstraintList) after the model is constructed. ```{doctest} >>> model = Model(objective) >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} >>> model += constraint1 >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1) ``` If the model has the objective function as an instance of the polynomial {py:class}`~amplify.Poly` class, addition and subtraction of the objective function are also possible. ```{doctest} >>> model += q[0, 0] * q[0, 1] >>> print(model) minimize: 2 q_{0,0} q_{0,1} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1) ``` ```{doctest} >>> model -= q[0, 0] >>> print(model) minimize: 2 q_{0,0} q_{0,1} - q_{0,0} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1) ``` ## Model attributes The {py:attr}`~amplify.Model.objective` property allows you to retrieve the objective function of the {py:class}`~amplify.Model` class. ```{testcode} from amplify import VariableGenerator, equal_to gen = VariableGenerator() q = gen.array("Binary", 2, 3) objective = q[0,0] * q[0,1] - q[0,2] constraint = equal_to(q[0,0] + q[0,1] - q[0,2], 0) model = objective + constraint ``` ```{doctest} >>> print(model.objective) q_{0,0} q_{0,1} - q_{0,2} ``` The {py:attr}`~amplify.Model.constraints` property allows the user to retrieve the constraints the {py:class}`~amplify.Model` class holds. This property returns an instance of the {py:class}`~amplify.ConstraintList` class. ```{doctest} >>> print(model.constraints) [q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1)] ``` ````{note} Note that the Model stores the objective function and constraints without copying them. Therefore, changing the objective function or constraints in the model will also change the variables before model construction. ```{doctest} model = Model(objective) model += q[0, 0] assert model.objective == objective ``` ```` ## Changing the constraint weight in the model After the model is constructed, you may want to change the weight of the constraint included in the model. ```{note} See "[](#penalty-weight)" for information on adjusting the weights of constraints. ``` In the following example, the weight of a constraint is doubled. ```{doctest} >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 1) >>> model.constraints[0] *= 2 >>> print(model) minimize: q_{0,0} q_{0,1} - q_{0,2} subject to: q_{0,0} + q_{0,1} - q_{0,2} == 0 (weight: 2) ```