JuMP looping through and matching two different objects

35 views Asked by At

I am defining an objective in JuMP. It looks like the below:

@objective(model, Min,sum(flowslist[(i,j,ct)]*total_cash_cost_ex_transp[(i,ct)]*10^6 for (i,j,ct) in flowslist))

And the problem variables are:

massflowtot = LpVariable.dicts("flow_total",edgelist,lowBound = 0,upBound=None,cat=LpContinuous)

massflowtype = LpVariable.dicts("flow_by_coaltype",flowslist,lowBound = 0,upBound=None,cat=LpContinuous) supplyitembynode = LpVariable.dicts("supply_coaltype_by_node",supplylist,lowBound = 0,upBound=None,cat=LpContinuous)

flowslist is a vector of tuples with three values. total_cash_cost_ex_transp is similarly a vector of Tuples with two values. How would I express this matching and multiplication? I am currently getting an invalid index error.

So flowslist is currently a vector of Tuple with (origin_node, destination_node, coal_group). We previously wrote this model in PuLP but we are hitting some hard and fast performance constraints. The dataframe is 499572 rows and those three columns. We have already pared the origin-destination pairs to deal with computational complexity because 10k nodes x 10k nodes x 12 coal types = PuLP goes boom. So I need to loop through each row's (origin, destination, coal type) and then match it to the total_cash_cost_ex_transp which is a dictionary with the keys being the (origin, destination) tuple.

The original PuLP code which works, but is very slow, is below:

for node in nodelist:
cn_coal_problem += (lpSum([supplyitembynode[(i,ct)]*CV_PJ_p_Mt_therm[ct] for (i,ct) in supplylist if i == node]) + 
                    lpSum([massflowtype[(i,j,ct)]*CV_PJ_p_Mt_therm[ct]*conversion_eff[i,j] for (i,j,ct) in flowslist if j == node]) >= 
                    elec_demand_PJ[node] + 
                    other_demand_PJ[node] + 
                    lpSum([massflowtype[(i,j,ct)]*CV_PJ_p_Mt_therm[ct]*conversion_eff[i,j] for (i,j,ct) in flowslist if i == node]))

Error output is below:

ArgumentError: invalid index: (String15("rwst_idno_1"), String15("rwst_idno_993"), String31("HCC_XXX")) of type Tuple{String15, String15, String31}
1

There are 1 answers

5
Oscar Dowson On

This error is unrelated to JuMP. You can't index a vector by the elements:

julia> x = [("a", "b"), ("b", "c")]
2-element Vector{Tuple{String, String}}:
 ("a", "b")
 ("b", "c")

julia> x[("a", "b")]
ERROR: ArgumentError: invalid index: ("a", "b") of type Tuple{String, String}
Stacktrace:
 [1] to_index(i::Tuple{String, String})
   @ Base ./indices.jl:300
 [2] to_index(A::Vector{Tuple{String, String}}, i::Tuple{String, String})
   @ Base ./indices.jl:277
 [3] to_indices
   @ ./indices.jl:333 [inlined]
 [4] to_indices
   @ ./indices.jl:325 [inlined]
 [5] getindex(A::Vector{Tuple{String, String}}, I::Tuple{String, String})
   @ Base ./abstractarray.jl:1170
 [6] top-level scope
   @ REPL[3]:1

It's hard to guess what you're trying to do without a reproducible example.

What is flowlist and total_cash_cost_ex_transp? What are the variables and what is the data?

Based on your edit, one option is:

using JuMP
import DataFrames
df = DataFrames.DataFrame(
    origin_node = ["A", "B"],
    destination_node = ["C", "C"],
    coal_group = ["x", "y"],
)
cost = Dict(("A", "C") => 1.0, ("B", "C") => 1.0)
model = Model()
df.x = @variable(model, x[1:size(df, 1)] >= 0)
@objective(
    model, 
    Min, 
    sum(cost[(r.origin_node, r.destination_node)] * r.x for r in eachrow(df)),
)

a better option might be

using JuMP
import DataFrames
df = DataFrames.DataFrame(
    origin_node = ["A", "B"],
    destination_node = ["C", "C"],
    coal_group = ["x", "y"],
)
cost_df = DataFrames.DataFrame(
    origin_node = ["A", "B"],
    destination_node = ["C", "C"],
    cost = [1.0, 1.0],
)
df_with_cost = DataFrames.innerjoin(
    df,
    cost_df;
    on = [:origin_node, :destination_node],
)
model = Model()
df_with_cost.x = @variable(model, x[1:size(df_with_cost, 1)] >= 0)
@objective(model, Min, df_with_cost.cost' * df_with_cost.x)

Note that a direct translation of your PuLP model into JuMP often has problems. You sometimes need to choose a different data structure.

The JuMP forum might be a better place for these questions. It's easier to have a back-and-forth conversation: https://discourse.julialang.org/c/domain/opt/13