如何在 Julia 中使用 JuMP 提取优化问题矩阵 A、b、c

How to extract optimization problem matrices A,b,c using JuMP in Julia

我使用符号变量和约束在 Julia-JuMP 中创建了一个优化模型,例如以下

using JuMP
using CPLEX

# model
Mod = Model(CPLEX.Optimizer) 

# sets
I = 1:2;

# Variables
x = @variable( Mod , [I] , base_name = "x" ) 
y = @variable( Mod , [I] , base_name = "y" )  

# constraints
Con1 = @constraint( Mod , [i in I] , 2 * x[i] + 3 * y[i] <= 100 )

# objective
ObjFun = @objective( Mod , Max , sum( x[i] + 2 * y[i] for i in I) ) ;

# solve 
optimize!(Mod)

我猜想 JuMP 在传递给求解器 CPLEX 之前以将 c'*x subj 最小化为 Ax < b 的形式创建了问题。我想提取矩阵 A、b、c。在上面的例子中,我希望是这样的:

A
2×4 Array{Int64,2}:
 2  0  3  0
 0  2  0  3

b
2-element Array{Int64,1}:
 100
 100

c
4-element Array{Int64,1}:
 1
 1
 2
 2

在 MATLAB 中,函数 prob2struct 可以做到这一点 https://www.mathworks.com/help/optim/ug/optim.problemdef.optimizationproblem.prob2struct.html

有没有JuMP函数可以做到这一点?

据我所知,这并不容易实现。

问题存储在底层 MathOptInterface (MOI) 特定数据结构中。例如,约束总是存储为 MOI.AbstractFunction - in - MOI.AbstractSetMOI.ObjectiveFunction也是如此。 (参见 MOI 文档:https://jump.dev/MathOptInterface.jl/dev/apimanual/#Functions-1

但是,您可以尝试重新计算 objective 函数项和矩阵向量形式的约束。

例如,假设您仍然拥有 JuMP.Model Mod,您可以通过键入以下内容进一步检查 objective 函数

using MathOptInterface
const MOI = MathOptInterface

# this only works if you have a linear objective function (the model has a ScalarAffineFunction as its objective)
obj = MOI.get(Mod, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}())

# take a look at the terms 
obj.terms
# from this you could extract your vector c
c = zeros(4)
for term in obj.terms
    c[term.variable_index.value] = term.coefficient
end
@show(c)

这确实给出了:c = [1.;1.;2.;2.].

您可以对基础 MOI 执行类似的操作。约束

# list all the constraints present in the model
cons = MOI.get(Mod, MOI.ListOfConstraints())
@show(cons)

在这种情况下,我们只有一种类型的约束,即 MOI.LessThan{Float64})

中的 (MOI.ScalarAffineFunction{Float64}
# get the constraint indices for this combination of F(unction) in S(et)
F = cons[1][1]
S = cons[1][2]
ci = MOI.get(Mod, MOI.ListOfConstraintIndices{F,S}())

你得到两个约束索引(存储在数组ci中),因为这个组合 F - in - S 有两个约束。 让我们仔细检查其中的第一个:

ci1 = ci[1]
# to get the function and set corresponding to this constraint (index):
moi_backend = backend(Mod)
f = MOI.get(moi_backend, MOI.ConstraintFunction(), ci1)

f 又是 MOI.ScalarAffineFunction 类型,它对应于 A = [a1; ...; am] 矩阵中的一行 a1。该行由:

a1 = zeros(4)
for term in f.terms
    a1[term.variable_index.value] = term.coefficient
end
@show(a1) # gives [2.0 0 3.0 0] (the first row of your A matrix)

要获取 b = [b1; ...; bm] 向量的相应第一个条目 b1,您必须查看相同约束索引 ci1:

的约束集
s = MOI.get(moi_backend, MOI.ConstraintSet(), ci1)
@show(s) # MathOptInterface.LessThan{Float64}(100.0)
b1 = s.upper

我希望这能让您对如何以 MathOptInterface 格式存储数据有一些直觉。

您必须对所有约束和所有约束类型执行此操作,并将它们堆叠为约束矩阵 A 和向量 b.

中的行

我自己没试过。但是MathProgBase包好像可以提供矩阵形式的A,b,c。

使用以下行:

Pkg.add("NLPModelsJuMP")

using NLPModelsJuMP

nlp = MathOptNLPModel(model) # the input "< model >" is the name of the model you created by JuMP before with variables and constraints (and optionally the objective function) attached to it.

x = zeros(nlp.meta.nvar)

b = NLPModelsJuMP.grad(nlp, x)

A = Matrix(NLPModelsJuMP.jac(nlp, x))