Search code examples
optimizationpyomo

TypeError: unhashable type: 'list' and unknown error in definition of objective function in pyomo


I am a new beginner, and I am trying to code an optimization problem ( a fixed cost multicommodity netwrok desing) via pyomo in Jupiter notebook. I import os, from collections import defaultdict, import networkx as nx, import pandas as pd, import pyomo.environ as pe, import pyomo.opt as po.

model.nodes = pe.Set(initialize=nodes)
model.edges = pe.Set(within=model.nodes*model.nodes, initialize=edges)
model.customer = pe.Set(initialize=customer)
model.p = pe.Set(initialize=p)

model.delta_neg = pe.Param(model.nodes, initialize=delta_neg, within=pe.Any, default=set())
model.delta_pos = pe.Param(model.nodes, initialize=delta_pos, within=pe.Any, default=set())
model.demand = pe.Param(model.customer, initialize=demand)
model.origin = pe.Param(model.customer, initialize=origin)
model.destination = pe.Param(model.customer, initialize=destination)
model.fixcost = pe.Param(model.edges, initialize=fixcost)
model.unitcost = pe.Param(model.edges, initialize=unitcost)
model.capacity = pe.Param(model.edges, initialize=capacity)
model.price = pe.Param(model.p, initialize=price)

model.x = pe.Var(model.edges, model.customer, within=pe.Binary)
model.y = pe.Var(model.edges, within=pe.Binary)
model.g = pe.Var(model.customer, within=pe.Binary)
model.alf= pe.Var(model.customer, model.p, within=pe.Binary)
model.z= pe.Var(model.edges, model.customer, within=pe.PositiveReals)
model.ua= pe.Var(model.nodes, model.customer, within=pe.PositiveReals)

the objective function:


def profit(model):
    return sum(model.fixcost[i, j] * model.y[i, j] * (-1) for (i, j) in model.edges) + sum(model.alf[customer,p] * model.demand[customer] * model.price[p] for custmer in model.customer for p in model.p) - sum(0.3 * model.alf[customer,p] * model.price[p]**2 for custmer in model.customer for p in model.p) - sum(model.demand[customer] * model.unitcost[i,j] * model.x[i,j,customer] for (i, j) in model.edges for custmer in model.customer) + sum(0.3 * model.unitcost[i,j] * model.z[i, j, customer] for (i, j) in model.edges for custmer in model.customer) - sum(2000000 * model.g[customer] for custmer in model.customer)
model.profit = pe.Objective(sense=pe.maximize, rule=profit)

when I write my objective function I receive this error

ERROR: Rule failed when generating expression for Objective profit with index
    None: DeveloperError: Internal Pyomo implementation error:
        'Unknown problem encountered when trying to retrieve index for component
        alf' Please report this to the Pyomo Developers.
ERROR: Constructing component 'profit' from data=None failed: DeveloperError:
    Internal Pyomo implementation error:
        'Unknown problem encountered when trying to retrieve index for component
        alf' Please report this to the Pyomo Developers.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~\anaconda3\lib\site-packages\pyomo\core\base\indexed_component.py in __getitem__(self, index)
    522         try:
--> 523             obj = self._data.get(index, _NotFound)
    524         except TypeError:

TypeError: unhashable type: 'list'

During handling of the above exception, another exception occurred:

DeveloperError                            Traceback (most recent call last)


DeveloperError: Internal Pyomo implementation error:
    'Unknown problem encountered when trying to retrieve index for component alf'
    Please report this to the Pyomo Developers.

I only bring the beginning and the end of the error.


Solution

  • Welcome to the site. You are getting bitten by a couple things here. But before that, if you have a piece of code that is producing an error, it is customary to include a minimum reproducible example such that somebody can copy/paste it and get the error you are working with. Your odds of getting a decent reply are a lot higher if you do so!

    So what is happening w/ your code... You have misspelled the word "customer" several times in your objective function as custmer. So when python tries to run the summation, it cannot find a local variable called customer for the indexing of things, so it goes back up in scope to your overall program and the stuffs in your original data list customer into the index and the bogus custmer variable does nothing you want it to do. But, there is no syntax error in your code, just an unfortunate typo, so you probably aren't seeing any static errors.

    So what can you do?

    1. Fix the typos
    2. Break up your ridiculously long objective function into individual expressions (see mine below). This will make them much easier to troubleshoot, and you get the added benefit of being able to see their value after you solve by doing things like pe.value(z2).
    3. Choose the names of your data elements more carefully. If you stick with the convention of naming collections of things as plural names you would have caught this much earlier... you have nodes, edges... why not customers as a data source?

    The below is a suggested approach, which builds without errors. I did not change customer --> customers though for clarity.


    import pyomo.environ as pe
    
    model = pe.ConcreteModel()
    
    nodes = [1, 2]
    edges = [(1, 2)]
    customer = ['Bob',]
    demand = {'Bob': 4}
    origin = {'Bob': 2}
    destination = {'Bob': 3}
    fixcost = { (1,2): 0.5}
    unitcost = fixcost
    capacity = fixcost
    
    p = [2,]
    price = {2:1}
    
    model.nodes = pe.Set(initialize=nodes)
    model.edges = pe.Set(within=model.nodes*model.nodes, initialize=edges)
    model.customer = pe.Set(initialize=customer)
    model.p = pe.Set(initialize=p)
    
    #model.delta_neg = pe.Param(model.nodes, initialize=delta_neg, within=pe.Any, default=set())
    #model.delta_pos = pe.Param(model.nodes, initialize=delta_pos, within=pe.Any, default=set())
    model.demand = pe.Param(model.customer, initialize=demand)
    model.origin = pe.Param(model.customer, initialize=origin)
    model.destination = pe.Param(model.customer, initialize=destination)
    model.fixcost = pe.Param(model.edges, initialize=fixcost)
    model.unitcost = pe.Param(model.edges, initialize=unitcost)
    model.capacity = pe.Param(model.edges, initialize=capacity)
    model.price = pe.Param(model.p, initialize=price)
    
    model.x = pe.Var(model.edges, model.customer, within=pe.Binary)
    model.y = pe.Var(model.edges, within=pe.Binary)
    model.g = pe.Var(model.customer, within=pe.Binary)
    model.alf= pe.Var(model.customer, model.p, within=pe.Binary)
    model.z= pe.Var(model.edges, model.customer, within=pe.PositiveReals)
    model.ua= pe.Var(model.nodes, model.customer, within=pe.PositiveReals)
    
    #OBJ components
    z1 = sum(model.fixcost[i, j] * model.y[i, j] * (-1) for (i, j) in model.edges)
    z2 = sum(model.alf[customer,p] * model.demand[customer] * model.price[p] for customer in model.customer for p in model.p)
    z3 = - sum(0.3 * model.alf[customer,p] * model.price[p]**2 for customer in model.customer for p in model.p)
    z4 = - sum(model.demand[customer] * model.unitcost[i,j] * model.x[i,j,customer] for (i, j) in model.edges for customer in model.customer)
    z5 = sum(0.3 * model.unitcost[i,j] * model.z[i, j, customer] for (i, j) in model.edges for customer in model.customer)
    z6 = - sum(2000000 * model.g[customer] for customer in model.customer)
    
    # make OBJ...
    z = z1 + z2 + z3 + z4 + z5 + z6
    model.profit = pe.Objective(sense=pe.maximize, expr=z)
    
    model.pprint()