Компактный способ сохранить результаты оптимизации JuMP в DataFrames

Я хотел бы эффективно сохранить все мои переменные и двойные переменные моей законченной lp-оптимизации. Мое текущее решение работает, но оно не элегантно и не подходит для больших программ оптимизации с множеством переменных и ограничений, потому что я определяю и продвигаю! каждую переменную в DataFrames отдельно. Есть ли способ перебирать переменные, используя all_variables() и all_constraints() для двойных? Во время итерации я хотел бы поместить результаты в DataFrames с именем индекса переменной в виде столбцов и сохранить 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,1,50
2,1,1,60 
3,1,1,145

person werderneo    schedule 20.01.2021    source источник


Ответы (2)


Предположительно, вы могли бы сделать что-то вроде:

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
person Oscar Dowson    schedule 20.01.2021

Благодаря Оскару я создал решение, которое может помочь автоматизировать извлечение результатов. Решение основано на соглашении об именах с использованием 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,n=s_n,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.

person werderneo    schedule 23.01.2021