I am trying to include a multivariate non-linear function in the scheduling problem from this tutorial. Basically, this function calculates a value based on the starting and idle times of the job at a given machine. It is a smooth concave function, no discontinuities.
I am using the 'piecewise_nd' function for that. For each pair (job, machine), I need to assign a different piecewise_nd block to a concrete model instance. The scheduling model code is identical to the tutorial and this is done in the piece of code below, which fails on "model.add_component(f'piecewise_{j}_{m}', piecewise)" with the message: AttributeError: 'piecewise_nd_cc' object has no attribute 'valid_model_component'
.
Does anyone know how to get around this, or have a better approach to add multiple n-dimensional piecewise models in a loop? Ideally, I wanted to achieve the same functionality available for the Piecewise object, which can be created with an index set as a parameter.
import pyomo.environ as pyo
from pyomo.core.kernel.piecewise_library.transforms_nd import piecewise_nd
from scipy.spatial import Delaunay
# the linearization auxiliary variable
model.cost = pyo.Var(model.TASKS, bounds=(0, None))
# apply the linearization
triangulation = Delaunay(points) # points: any 2-d array
values = f(*triangulation.points.T)
for j,m in model.TASKS:
var_list = [model.start[j,m], model.idle[j,m]]
piecewise = piecewise_nd(triangulation,
values=values,
input=var_list,
output=model.cost[j,m],
bound='eq',
repn='cc')
# add the piecewise_nd block to the model
model.add_component(f'piecewise_{j}_{m}', piecewise)
# set the objective
model.objective = pyo.Objective(expr = sum([model.cost[j,m] for j,m in model.TASKS]), sense = pyo.minimize)
I tried the approach from this question, but the add_component
function is not working properly with the piecewise_nd
object, throwing the error above.
EDIT
The full code is available in this notebook
In the future, it would be helpful to post the entire error stack trace and not just the message. It is also challenging to debug your model / verify a solution, as you have not provided a complete example.
That said, the kernel library is an experimental / development library and is not 100% compatible with the rest of Pyomo. In particular, it looks like kernel modeling objects do not all implement the full Component API and cause an error in add_component()
. Based on the kernel piecewise unit tests, I think you can work around the problem by using:
setattr(model, f'piecewise_{j}_{m}', piecewise)
instead of
model.add_component(f'piecewise_{j}_{m}', piecewise)
Finally, I should point out that there is active development work on a new multivariate piecewise capability (in pyomo.contrib.piecewise
) that aims to be 100% compatible with the core Pyomo AML.