在 DataFrames 中保存 JuMP 优化结果的紧凑方法

问题描述

我想以有效的方式保存我完成的 lp 优化的所有变量和双变量。我当前的解决方案有效,但既不优雅也不适合具有许多变量和约束的大型优化程序,因为我定义并推送!每个单独的变量分别放入 DataFrame 中。有没有办法使用 all_variables() 和 all_constraints() 来迭代变量?在迭代时,我想将结果推送到 DataFrame 中,并将变量索引名称作为列,并将 DataFrame 保存在 Dict() 中。 一个概念的例子是变量:

Result_vars = Dict()
for vari in all_variables(Model)
Resul_vars["vari"] = DataFrame(data=[indexval(vari),value(vari)],columns=[index(vari),"Value"]) 
end

JuMP 和 DataFrame 中声明变量的外观示例:

@variable(Model,p[t=s_time,n=s_n,m=s_m],lower_bound=0,base_name="Expected production")

而 Result_vars[p] 应大致如下:

t,n,m,Value
1,1,50
2,60 
3,145

解决方法

大概,你可以这样做:

x = all_variables(model)
DataFrame(
    name = variable_name.(x),Value = value.(x),)

如果你想要一些更复杂的结构,你需要编写自定义代码。

T,N,M,primal_solution = [],[],[]
for t in s_time,n in s_n,m in s_m
    push!(T,t)
    push!(N,n)
    push!(M,m)
    push!(primal_solution,value(p[t,n,m]))
end
DataFrame(t = T,n = N,m = M,Value = primal_solution)

请参阅此处了解限制条件:https://jump.dev/JuMP.jl/stable/constraints/#Accessing-constraints-from-a-model-1。你想要这样的东西:

for (F,S) in list_of_constraint_types(model)
    for con in all_constraints(model,F,S)
        @show dual(con)
    end
end
,

感谢 Oscar,我构建了一个有助于自动提取结果的解决方案。 解决方案是围绕在变量定义中使用 base_name 的命名约定构建的。可以将变量定义复制粘贴到 base_name 后跟 :。例如:

@variable(Model,p[t=s_time,n=s_n,m=s_m],lower_bound=0,base_name="p[t=s_time,m=s_m]:")

命名约定和语法可以更改,注释可以例如添加,或者不能定义 base_name。以下函数将 base_name 划分为变量名、集合(如果需要)和索引:

function var_info(vars::VariableRef)
    split_conv = [":","]","[",","]
    x_str = name(vars)
    if occursin(":",x_str)
        x_str = replace(x_str," " => "") #Deletes all spaces
        x_name,x_index = split(x_str,split_conv[1]) #splits raw variable name+ sets and index
        x_name = replace(x_name,split_conv[2] => "")
        x_name,s_set = split(x_name,split_conv[3])#splits raw variable name and sets
        x_set = split(s_set,split_conv[4])

        x_index = replace(x_index,split_conv[2] => "")
        x_index = replace(x_index,split_conv[3] => "")
        x_index = split(x_index,split_conv[4])
        return (x_name,x_set,x_index)
    else
        println("Var base_name not properly defined. Special Syntax required in form     var[s=set]:  ")
    end
    
end

接下来的函数为原始解决方案(“值”)创建列和索引值以及列。

function create_columns(x)
    col_ind=[String(var_info(x)[2][col]) for col in 1:size(var_info(x)[2])[1]]
    cols = append!(["Value"],col_ind)
    return cols
end

function create_index(x)
    col_ind=[String(var_info(x)[3][ind]) for ind in 1:size(var_info(x)[3])[1]]
    index = append!([string(value(x))],col_ind)
    return index
end

function create_sol_matrix(varss,model)
    nested_sol_array=[create_index(xx) for xx in all_variables(model) if varss[1]==var_info(xx)[1]]
    sol_array=hcat(nested_sol_array...)
    return sol_array
end

最后,最后一个函数创建了 Dict,它以前面提到的样式保存 DataFrames 中变量的所有结果:

function create_var_dict(model)
    Variable_dict=Dict(vars[1]
            =>DataFrame(Dict(vars[2][1][cols] 
                =>create_sol_matrix(vars,model)[cols,:] for cols in 1:size(vars[2][1])[1]))
                    for vars in unique([[String(var_info(x)[1]),[create_columns(x)]] for x in all_variables(model)]))
    return Variable_dict
end

将这些函数添加到您的脚本中后,您可以通过调用 create_var_dict() 来简单地检索优化后变量的所有解:

var_dict = create_var_dict(model)

请注意:它们是嵌套函数。当您更改命名约定时,您可能还必须更新其他函数。如果您添加更多评论,则必须避免使用 [],。 这个解决方案显然远非最佳。我相信回归到 MOI 可能会有更有效的解决方案。