21 September 2022
In this article we continue the Python Production mix series, using the Pyomo library. Specifically, we build Model 6, which changes Model 5 to:
- Declare the model as a Pyomo
pyo.AbstractModel
, rather than as apyo.ConcreteModel
. - Read the data from a
dat
file rather than ajson
file.
These changes show that, contrary to how abstract and concrete models are portrayed in most blogs, there is actually little difference between abstract and concrete Pyomo models.
Articles in this series
Articles in the Python Production mix series:
- Python optimization Rosetta Stone
- Production mix - Model 1, Pyomo concrete
- Production mix - Model 2, Pyomo separate data
- Production mix - Model 3, Pyomo external data
- Production mix - Model 4, Pyomo json file
- Production mix - Model 5, Pyomo using def
- Production mix - Model 6, Pyomo abstract
- Production mix - Model 7, PuLP
- Production mix - Model 8, OR-Tools
- Production mix - Model 9, Gekko
- Production mix - Model 10, CVXPY
- Production mix - Model 11, SciPy
- Production mix - Conclusions
Download the models
The model is available on GitHub.
Formulation for Model 6
For this model, we're using the same general formulation that we used for Model 2.
Model 6 Python code
Import dependencies
The first task is to import the libraries that are needed for our program. As shown in Figure 1, we aren't using a json file, so we don't need the os
and json
libraries that we imported in Model 5.
Data file
The data for Model 6 is shown in Figure 2. 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.
Declarations
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 3. Though we can declare the domains, such as pyo.NonNegativeReals
.
Define the model
The model definition, as shown in Figure 4, 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.
Solve model
As shown in Figure 5, 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.
Process results
The code for processing the solver result, as shown in Figure 6, is the same as for Model 5 except that we refer to Instance
rather than Model
.
Write output
The code for writing the output, as shown in Figure 7, 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 8. 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.
Abstract versus Concrete models
Next steps
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.
Conclusion
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.