For this model, we're using the same general formulation that we used for Model 5, as shown in Figure 1.
Model 6 Python code
The first task is to import the libraries that are needed for our program. As shown in Figure 2, we aren't using a json file, so we don't need the os and json libraries that we imported in Model 5.
The data for Model 6 is shown in Figure 3. Unlike Model 5, where we read json format data and assign it to Pyomo Param data structures, here we define the data directly in param data structures. Note the different capitalization of the two structures – uppercase for parameters defined in the model, and lowercase for parameters defined in a dat file. The same convention applies to sets.
Note that, unlike concrete models, we don't load the data at this stage. This is the essential difference between the two types of Pyomo model. That is:
pyo.ConcreteModel. Data is loaded before the constraints and objective function are defined.
pyo.AbstractModel. The constraints are objective function are defined first, with the data loaded only when we solve the model.
We declare an pyo.AbstractModel, rather than a pyo.ConcreteModel. Because we have not loaded the data, the declarations are empty sets and parameters, as shown in Figure 4. Though we can declare the domains, such as pyo.NonNegativeReals.
Define the model
The model definition, as shown in Figure 5, is the same as for Model 5.
In a more complex model, the concrete and abstract model definitions may not be the same. Specifically, in a concrete mode, we may use the data to make decisions within the constraint and objective function rules. That is not possible in a pure abstract model – though we could read some data, to inform decision making, but there is typically little advantage in adopting a hybrid approach.
As shown in Figure 6, we create an instance of an abstract model by loading the data just before we solve the model. Having created an instance, we need to refer to our Instance object rather than our Model object. In abstract models, a common error is to refer to the model definition rather than its instance.
The code for processing the solver result, as shown in Figure 7, is the same as for Model 5 except that we refer to Instance rather than Model.
The code for writing the output, as shown in Figure 8, is almost the same as for Model 5, except that, again, we refer to Instance rather than Model.
When we find an optimal solution, the output is shown in Figure 9. This output is the same as for Model 5.
Evaluation of this model
Model 6 is our final Pyomo model in this series of articles. This model translates the concrete Model 5 into an abstract model.
Most blog articles about Pyomo models suggest that there is a substantial difference between concrete and abstract models. A model like our Model 1 is often used as a typical concrete model, while a model like our Model 6 is used as a typical abstract model. When presented that way, there is indeed a substantial difference between the two types of model.
However, a fairer comparison is between our Model 5 and Model 6. When presented this way, there is actually little difference between the two model types. As the Pyomo documentation says:
Python programmers will probably prefer to write concrete models, while users of some other algebraic modeling languages may tend to prefer to write abstract models. The choice is largely a matter of taste; some applications may be a little more straightforward using one or the other.
So far in this series, we've explored the Pyomo library quite extensively. Next, we'll continue our Production mix series by implementing the model using other Python modelling libraries. Specifically, we'll use the PuLP, OR Tools, Gekko, CVXPY, and SciPy libraries to implement the same model. By using different libraries, we'll get some insight into their similarities and differences, along with their relative strengths and weaknesses.
This article completes the Pyomo part of this series. Compared with models 1 to 5, which use Pyomo's concrete model type, here we use Pyomo's abstract model type. It turns out that there isn't much difference between the two model types, with the choice between them being largely a matter of taste.
In the next article, we'll start using different libraries to build the same Production mix model.
If you would like to know more about this model, or you want help with your own models, then please contact us.