Search code examples
pyomo

Add multiple piecewise_nd blocks to pyomo model


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


Solution

  • 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.