Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement set_start_value for constraint indices #2835

Closed
blegat opened this issue Dec 21, 2021 · 2 comments · Fixed by #2847
Closed

Implement set_start_value for constraint indices #2835

blegat opened this issue Dec 21, 2021 · 2 comments · Fixed by #2847
Milestone

Comments

@blegat
Copy link
Member

blegat commented Dec 21, 2021

Should it be set_start_value or set_primal_start_value given that for the dual it's set_dual_start_value and for variables it is set_start_value ?

cc @kalmarek

@kalmarek
Copy link

kalmarek commented Feb 3, 2022

I'm not sure where to report this error, so I'll do it here.

Env:

JuMP-0.22.2
SCS-0.8.2 or SCS-0.9.0

MWE:

using JuMP
using SCS

function setwarmstart!(model::JuMP.Model, warmstart)
    constraint_map = Dict(
        ct => JuMP.all_constraints(model, ct...) for
        ct in JuMP.list_of_constraint_types(model)
    )

    JuMP.set_start_value.(JuMP.all_variables(model), warmstart.primal)

    for (ct, idx) in pairs(constraint_map)
        JuMP.set_start_value.(idx, warmstart.slack[ct])
        JuMP.set_dual_start_value.(idx, warmstart.dual[ct])
    end
    return model
end

function getwarmstart(model::JuMP.Model)
    constraint_map = Dict(
        ct => JuMP.all_constraints(model, ct...) for
        ct in JuMP.list_of_constraint_types(model)
    )

    primal = value.(JuMP.all_variables(model))

    slack = Dict(k => value.(v) for (k, v) in constraint_map)
    duals = Dict(k => JuMP.dual.(v) for (k, v) in constraint_map)

    return (primal = primal, dual = duals, slack = slack)
end

using Random
using SparseArrays

let (m, n, k) = (5, 10, 3)
    Random.seed!(123)
    A = rand(m, n)
    b = A * rand(n)
    c = rand(n)
    Bp = rand(1:n, k, k)
    B = rand(k, k)

    model = Model(optimizer_with_attributes(SCS.Optimizer, "warm_start" => true))
    @variable(model, x[1:n] >= 0.0)
    @constraint(model, A * x .== b)

    @objective(model, Min, c'x)
    optimize!(model)

    warmstart = getwarmstart(model)

    model2 = setwarmstart!(model, warmstart)
    optimize!(model2)
end

results in warmstarting just fine, however if I add a psd constraint like this:

@constraint(model, B.*x[Bp] in PSDCone())

setwarmstart! throws

ERROR: MathOptInterface.UnsupportedAttribute{MathOptInterface.ConstraintPrimalStart}: Attribute MathOptInterface.ConstraintPrimalStart() is not supported by the model.
Stacktrace:
  [1] set(model::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, attr::MathOptInterface.ConstraintPrimalStart, bridge::MathOptInterface.Bridges.Constraint.SquareBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeTriangle, MathOptInterface.PositiveSemidefiniteConeSquare}, value::Vector{Float64})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge.jl:127
  [2] (::MathOptInterface.Bridges.var"#3#4"{typeof(MathOptInterface.set), MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.ConstraintPrimalStart, Tuple{Vector{Float64}}})(bridge::MathOptInterface.Bridges.Constraint.SquareBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeTriangle, MathOptInterface.PositiveSemidefiniteConeSquare})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge_optimizer.jl:308
  [3] (::MathOptInterface.Bridges.var"#1#2"{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}, MathOptInterface.Bridges.var"#3#4"{typeof(MathOptInterface.set), MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.ConstraintPrimalStart, Tuple{Vector{Float64}}}})()
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge_optimizer.jl:293
  [4] call_in_context(map::MathOptInterface.Bridges.Variable.Map, bridge_index::Int64, f::MathOptInterface.Bridges.var"#1#2"{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}, MathOptInterface.Bridges.var"#3#4"{typeof(MathOptInterface.set), MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.ConstraintPrimalStart, Tuple{Vector{Float64}}}})
    @ MathOptInterface.Bridges.Variable ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/Variable/map.jl:455
  [5] call_in_context
    @ ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/Variable/map.jl:486 [inlined]
  [6] call_in_context
    @ ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge_optimizer.jl:290 [inlined]
  [7] call_in_context
    @ ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge_optimizer.jl:305 [inlined]
  [8] _set_substituted(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, attr::MathOptInterface.ConstraintPrimalStart, ci::MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}, value::Vector{Float64})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge_optimizer.jl:1278
  [9] set
    @ ~/.julia/packages/MathOptInterface/eoIu0/src/Bridges/bridge_optimizer.jl:1291 [inlined]
 [10] set(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{SCS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, attr::MathOptInterface.ConstraintPrimalStart, index::MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}, value::Vector{Float64})
    @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/eoIu0/src/Utilities/cachingoptimizer.jl:760
 [11] set(model::Model, attr::MathOptInterface.ConstraintPrimalStart, cr::ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}, SquareMatrixShape}, value::Vector{Float64})
    @ JuMP ~/.julia/packages/JuMP/lnUbA/src/JuMP.jl:1321
 [12] set_start_value(con_ref::ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}, SquareMatrixShape}, value::Matrix{Float64})
    @ JuMP ~/.julia/packages/JuMP/lnUbA/src/constraints.jl:148
 [13] _broadcast_getindex_evalf
    @ ./broadcast.jl:670 [inlined]
 [14] _broadcast_getindex
    @ ./broadcast.jl:643 [inlined]
 [15] getindex
    @ ./broadcast.jl:597 [inlined]
 [16] macro expansion
    @ ./broadcast.jl:961 [inlined]
 [17] macro expansion
    @ ./simdloop.jl:77 [inlined]
 [18] copyto!
    @ ./broadcast.jl:960 [inlined]
 [19] copyto!
    @ ./broadcast.jl:913 [inlined]
 [20] copy
    @ ./broadcast.jl:885 [inlined]
 [21] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(set_start_value), Tuple{Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeSquare}}}, Vector{Matrix{Float64}}}})
    @ Base.Broadcast ./broadcast.jl:860
 [22] setwarmstart!(model::Model, warmstart::NamedTuple{(:primal, :dual, :slack), Tuple{Vector{Float64}, Dict{Tuple{DataType, DataType}, Vector}, Dict{Tuple{DataType, DataType}, Vector}}})
    @ Main ./REPL[5]:10
 [23] top-level scope
    @ REPL[11]:20

any help would be much appreciated

@odow
Copy link
Member

odow commented Feb 3, 2022

Okay. It works if you have @constraint(model, Symmetric(B.*x[Bp]) in PSDCone()), so we're missing a method to pass start values in the bridge between a square PSD cone and a triangular PSD cone.

We should open an issue in MOI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants