I haven't had trouble with pickling a Pyomo model before, but now a recursion error is being raised when trying to pickle Expressions.
Interestingly, the error can be avoided in the example below via a couple of ways:
...but I don't know why these would fix the error, nor are they workable solutions for the actual optimization model I am trying to pickle.
The following example generates the error from the pickling of just a single Expression. (I am using pyomo=5.6.2, cloudpickle=0.6.1, and python=3.7.4)
import cloudpickle
import pyomo.environ as pyo
test_model = pyo.ConcreteModel()
# A set is added.
set_elements = list(range(0, 500))
test_model.my_set = pyo.Set(initialize=set_elements)
# A parameter is added.
param_values = dict()
for e in set_elements:
param_values[e] = 1
test_model.my_param = pyo.Param(test_model.my_set, initialize=param_values, mutable=True)
# An expression is added.
def calculation_rule(mdl):
return sum(mdl.my_param[e] for e in mdl.my_set)
test_model.calculation_expr = pyo.Expression(rule=calculation_rule)
# We attempt to pickle the expression.
pickle_str = cloudpickle.dumps(test_model.calculation_expr)
The last line of the above code raises the following exception:
PicklingError: Could not pickle object as excessively deep recursion required.
QUESTION: Do I need to modify the way the Expression is written in order to pickle the model, or should I save the model using something other than Cloudpickle?
Thanks in advance for any help!
One fix is to use Pyomo's quicksum
instead of Python's sum
. It leads to more compact expression trees and seems to fix the recursion issue you're seeing:
# An expression is added.
def calculation_rule(mdl):
return pyo.quicksum(mdl.my_param[e] for e in mdl.my_set)
test_model.calculation_expr = pyo.Expression(rule=calculation_rule)
Documentation here.