Как мне определить AMPL-подобные наборы и параметры в Julia + JuMP?

Мне нужно определить некоторый постоянный параметр в Julia + JuMP, аналогично тому, что вы делаете в AMPL, когда определяете

set A := a0 a1 a2;

param p :=
a0 1
a1 5
a2 10 ;

Как мне определить что-то вроде A и p в Julia?


person HAL9000    schedule 09.07.2014    source источник


Ответы (2)


Сам JuMP не определяет особого синтаксиса для наборов индексов, помимо того, что доступно в Julia. Так, например, вы можете определить

A = [:a0, :a1, :a2]

где :a0 определяет символ.

Если вы хотите проиндексировать переменную по этому набору, используйте следующий синтаксис:

m = Model()
@variable(m, x[A])

JuMP также не делает различий между данными и моделью так же, как AMPL, поэтому нет реальной концепции параметра. Вместо этого вы просто предоставляете данные в то время, когда они используются. Если я правильно понимаю ваш вопрос, вы можете сделать что-то вроде

p = Dict(:a0 => 1, :a1 => 5, :a2 => 10)
@constraint(m, sum(p[i]*x[i] for i in A) <= 20)

Это добавит ограничение

x[a0] + 5 x[a1] + 10 x[a2] <= 20

Где мы определяем p как словарь Julia. Здесь нет ничего специфичного для JuMP, и действительно любое выражение julia может быть использовано в качестве коэффициента. Так же легко можно было сказать

@constraint(m, sum(foo(i)*x[i] for i in A) <= 20)

Где foo - произвольная функция Джулии, которая может выполнять поиск в базе данных, вычислять цифры числа пи и т. Д.

person mlubin    schedule 09.07.2014
comment
Этот ответ очень полезен. В любом случае я думаю, что данных не должно быть внутри кода. Я вижу два решения: 1) по возможности прочтите константы из файла. 2) сгенерировать код через скрипт, который заполняет данные, прочитанные, например, из xml. - person HAL9000; 10.07.2014
comment
Конечно, разумно читать данные из файла. Философия JuMP заключается в том, чтобы позволить пользователю решать, как структурировать ввод, а не навязывать определенные форматы файлов. Например, выше вы можете заполнить p из файла, используя собственные функции ввода-вывода Джулии или LightXML.jl пакет. - person mlubin; 10.07.2014
comment
Большое спасибо, я пытаюсь что-то поискать по этому поводу. - person HAL9000; 10.07.2014
comment
@mlubin Как бы вы продолжили определение цели? Я пробовал с @objective(m, Max, sum(x[i]+p[i] for i in A)), но это не сработало. На самом деле, Julia 0.5 выдает мне ошибку в операторе ограничения, когда вы его написали: LoadError: indexing Array{Pair{Symbol,Int64},1} with types Tuple{Symbol} is not supported - person Antonello; 28.01.2017
comment
Я исправил ошибку в определении p. Теперь код должен работать. - person mlubin; 29.01.2017

Я не мог получить оригинальный ответ о работе @mlubin. Кроме того, во многих примерах в Интернете используется индексирование на основе позиции, что мне не кажется таким естественным, поэтому я переписал trnsport.gms пример учебника GAMS, в котором вместо этого используются словари ... которые кажутся гораздо более близкими к" наборам "gams / amp ..

#=
Transposition in JuMP of the basic transport model used in the GAMS tutorial

This problem finds a least cost shipping schedule that meets requirements at markets and supplies at factories.

- Original formulation: Dantzig, G B, Chapter 3.3. In Linear Programming and Extensions.
Princeton University Press, Princeton, New Jersey, 1963.
- Gams implementation: This formulation is described in        detail in:
Rosenthal, R E, Chapter 2: A GAMS Tutorial. In GAMS: A User's Guide.
The Scientific Press, Redwood City, California, 1988.
- JuMP implementation: Antonello Lobianco
=#

using JuMP, DataFrames

# Sets
plants  = ["seattle","san_diego"]          # canning plants
markets = ["new_york","chicago","topeka"]  # markets

# Parameters
a = Dict(              # capacity of plant i in cases
  "seattle"   => 350,
  "san_diego" => 600,
)
b = Dict(              # demand at market j in cases
  "new_york"  => 325,
  "chicago"   => 300,
  "topeka"    => 275,
)

#  distance in thousands of miles
d_table = wsv"""
plants     new_york  chicago  topeka
seattle    2.5       1.7      1.8
san_diego  2.5       1.8      1.4
"""
d = Dict( (r[:plants],m) => r[Symbol(m)] for r in       eachrow(d_table), m in markets)

f = 90 # freight in dollars per case per thousand miles

c = Dict() # transport cost in thousands of dollars per case ;
[ c[p,m] = f * d[p,m] / 1000 for p in plants, m in markets]

# Model declaration
trmodel = Model() # transport model

# Variables
@variables trmodel begin
    x[p in plants, m in markets] >= 0 # shipment quantities in cases
end

# Constraints
@constraints trmodel begin
    supply[p in plants],   # observe supply limit at plant p
        sum(x[p,m] for m in markets)  <=  a[p]
    demand[m in markets],  # satisfy demand at market m
        sum(x[p,m] for p in plants)  >=  b[m]
 end

# Objective
@objective trmodel Min begin
    sum(c[p,m]*x[p,m] for p in plants, m in markets)
end

print(trmodel)

status = solve(trmodel)

if status == :Optimal
    println("Objective value: ", getobjectivevalue(trmodel))
    println("Shipped quantities: ")
    println(getvalue(x))
    println("Shadow prices of supply:")
    [println("$p = $(getdual(supply[p]))") for p in plants]
    println("Shadow prices of demand:")
    [println("$m = $(getdual(demand[m]))") for m in markets]

else
    println("Model didn't solved")
    println(status)
end

# Expected result:
# obj= 153.675
#['seattle','new-york']   = 50
#['seattle','chicago']    = 300
#['seattle','topeka']     = 0
#['san-diego','new-york'] = 275
#['san-diego','chicago']  = 0
#['san-diego','topeka']   = 275

Версия с гораздо большим количеством комментариев доступна в моем соответствующем сообщении блога.

person Antonello    schedule 28.01.2017