如何在 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.AbstractSet
。 MOI.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))
我使用符号变量和约束在 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.AbstractSet
。 MOI.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))