diff --git a/src/MathOptInterfaceMosek.jl b/src/MathOptInterfaceMosek.jl index 8b5bf30..44d3f89 100644 --- a/src/MathOptInterfaceMosek.jl +++ b/src/MathOptInterfaceMosek.jl @@ -54,6 +54,7 @@ struct ConstraintMap xs_reals :: Dict{Int64,Int} # (VectorOfVariables,Reals) -> constraint number xs_qcone :: Dict{Int64,Int} # (VectorOfVariables,SecondOrderCone) -> constraint number xs_rqcone :: Dict{Int64,Int} # (VectorOfVariables,RotatedSecondOrderCone) -> constraint number + xs_econe :: Dict{Int64,Int} # (VectorOfVariables,ExponentialCone) -> constraint number xs_psdconetriangle :: Dict{Int64,Int} # (VectorOfVariables,PositiveSemidefiniteConeTriangle) -> constraint number axb_lessthan :: Dict{Int64,Int} # (ScalarAffineFunction,LessThan) -> constraint number @@ -71,10 +72,11 @@ struct ConstraintMap axbs_reals :: Dict{Int64,Int} # (VectorAffineFunction,Reals) -> constraint number axbs_qcone :: Dict{Int64,Int} # (VectorAffineFunction,SecondOrderCone) -> constraint number axbs_rqcone :: Dict{Int64,Int} # (VectorAffineFunction,RotatedSecondOrderCone) -> constraint number + axbs_econe :: Dict{Int64,Int} # (VectorAffineFunction,ExponentialCone) -> constraint number axbs_psdconetriangle :: Dict{Int64,Int} # (VectorAffineFunction,PositiveSemidefiniteConeTriangle) -> constraint number end -ConstraintMap() = ConstraintMap([Dict{Int64,Int}() for i in 1:30]...) +ConstraintMap() = ConstraintMap([Dict{Int64,Int}() for i in 1:32]...) select(cm::ConstraintMap,::Type{MOI.SingleVariable}, ::Type{MOI.LessThan{Float64}}) = cm.x_lessthan select(cm::ConstraintMap,::Type{MOI.SingleVariable}, ::Type{MOI.GreaterThan{Float64}}) = cm.x_greaterthan select(cm::ConstraintMap,::Type{MOI.SingleVariable}, ::Type{MOI.EqualTo{Float64}}) = cm.x_equalto @@ -89,6 +91,7 @@ select(cm::ConstraintMap,::Type{MOI.VectorOfVariables}, ::Type{MOI.Ze select(cm::ConstraintMap,::Type{MOI.VectorOfVariables}, ::Type{MOI.Reals}) = cm.xs_reals select(cm::ConstraintMap,::Type{MOI.VectorOfVariables}, ::Type{MOI.SecondOrderCone}) = cm.xs_qcone select(cm::ConstraintMap,::Type{MOI.VectorOfVariables}, ::Type{MOI.RotatedSecondOrderCone}) = cm.xs_rqcone +select(cm::ConstraintMap,::Type{MOI.VectorOfVariables}, ::Type{MOI.ExponentialCone}) = cm.xs_econe select(cm::ConstraintMap,::Type{MOI.VectorOfVariables}, ::Type{MOI.PositiveSemidefiniteConeTriangle}) = cm.xs_psdconetriangle select(cm::ConstraintMap,::Type{MOI.ScalarAffineFunction{Float64}},::Type{MOI.LessThan{Float64}}) = cm.axb_lessthan select(cm::ConstraintMap,::Type{MOI.ScalarAffineFunction{Float64}},::Type{MOI.GreaterThan{Float64}}) = cm.axb_greaterthan @@ -104,6 +107,7 @@ select(cm::ConstraintMap,::Type{MOI.VectorAffineFunction{Float64}},::Type{MOI.Ze select(cm::ConstraintMap,::Type{MOI.VectorAffineFunction{Float64}},::Type{MOI.Reals}) = cm.axbs_reals select(cm::ConstraintMap,::Type{MOI.VectorAffineFunction{Float64}},::Type{MOI.SecondOrderCone}) = cm.axbs_qcone select(cm::ConstraintMap,::Type{MOI.VectorAffineFunction{Float64}},::Type{MOI.RotatedSecondOrderCone}) = cm.axbs_rqcone +select(cm::ConstraintMap,::Type{MOI.VectorAffineFunction{Float64}},::Type{MOI.ExponentialCone}) = cm.axbs_econe select(cm::ConstraintMap,::Type{MOI.VectorAffineFunction{Float64}},::Type{MOI.PositiveSemidefiniteConeTriangle}) = cm.axbs_psdconetriangle Base.getindex{F,D}(cm::ConstraintMap,r :: MOI.ConstraintIndex{F,D}) = select(cm,F,D)[r.value] @@ -231,6 +235,7 @@ using MathOptInterfaceUtilities const MOIU = MathOptInterfaceUtilities @bridge GeoMean MOIU.GeoMeanBridge () () (GeometricMeanCone,) () () () (VectorOfVariables,) (VectorAffineFunction,) @bridge RootDet MOIU.RootDetBridge () () (RootDetConeTriangle,) () () () (VectorOfVariables,) (VectorAffineFunction,) +@bridge LogDet MOIU.LogDetBridge () () (LogDetConeTriangle,) () () () (VectorOfVariables,) (VectorAffineFunction,) function MosekInstance(; kws...) t = maketask() @@ -262,7 +267,7 @@ function MosekInstance(; kws...) if ! be_quiet Mosek.putstreamfunc(t,Mosek.MSK_STREAM_LOG,m -> print(m)) end - RootDet{Float64}(GeoMean{Float64}( + LogDet{Float64}(RootDet{Float64}(GeoMean{Float64}( MosekModel(t,# task 0, # public numvar ConstraintMap(), # public constraints @@ -280,7 +285,7 @@ function MosekInstance(; kws...) 0, # cone counter Mosek.MSK_RES_OK, MosekSolution[]) # trm - )) + ))) catch Mosek.deletetask(t) rethrow() diff --git a/src/attributes.jl b/src/attributes.jl index cd0dada..967e8cd 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -242,7 +242,7 @@ function MOI.get!( # It is in fact a real constraint and cid is the id of an ordinary constraint barvaridx = - m.c_block_slack[-cid] - output[1:length(output)] = sympackedLtoU(getbarxj(m.task,whichsol,barvaridx)) + output[1:length(output)] = reorderval(getbarxj(m.task,whichsol,barvaridx), MOI.PositiveSemidefiniteConeTriangle) end # Any other domain for variable vector @@ -259,7 +259,7 @@ function MOI.get!{D}( idxs = getindexes(m.xc_block,xcid) subj = m.xc_idxs[idxs] - output[1:length(output)] = m.solutions[attr.N].xx[subj] + output[1:length(output)] = reorderval(m.solutions[attr.N].xx[subj], D) end function MOI.get{D}(m ::MosekModel, @@ -270,8 +270,6 @@ function MOI.get{D}(m ::MosekModel, m.solutions[attr.N].xc[subi] end - - function MOI.get!{D}( output::Vector{Float64}, m ::MosekModel, @@ -286,10 +284,10 @@ function MOI.get!{D}( elseif m.c_block_slack[cid] > 0 # qcone slack xid = m.c_block_slack[cid] xsubj = getindexes(m.x_block, xid) - output[1:length(output)] = m.solutions[attr.N].xx[xsubj] + output[1:length(output)] = reorderval(m.solutions[attr.N].xx[xsubj], getconeset(m, cid)) else # psd slack xid = - m.c_block_slack[cid] - output[1:length(output)] = sympackedLtoU(getbarxj(m.task,m.solutions[attr.N].whichsol,Int32(xid))) + output[1:length(output)] = reorderval(getbarxj(m.task,m.solutions[attr.N].whichsol,Int32(xid)), MOI.PositiveSemidefiniteConeTriangle) end end @@ -366,7 +364,7 @@ function MOI.get!( # It is in fact a real constraint and cid is the id of an ordinary constraint barvaridx = - m.c_block_slack[-cid] - dual = sympackedLtoU(getbarsj(m.task,whichsol,barvaridx)) + dual = reorderval(getbarsj(m.task,whichsol,barvaridx), MOI.PositiveSemidefiniteConeTriangle) if (getobjsense(m.task) == MSK_OBJECTIVE_SENSE_MINIMIZE) output[1:length(output)] = dual else @@ -390,25 +388,25 @@ function MOI.get!{D}( if (getobjsense(m.task) == MSK_OBJECTIVE_SENSE_MINIMIZE) if mask & boundflag_lower != 0 && mask & boundflag_upper != 0 - output[1:length(output)] = m.solutions[attr.N].slx[subj] - m.solutions[attr.N].sux[subj] + output[1:length(output)] = reorderval(m.solutions[attr.N].slx[subj] - m.solutions[attr.N].sux[subj], D) elseif (mask & boundflag_lower) != 0 - output[1:length(output)] = m.solutions[attr.N].slx[subj] + output[1:length(output)] = reorderval(m.solutions[attr.N].slx[subj], D) elseif (mask & boundflag_upper) != 0 - output[1:length(output)] = - m.solutions[attr.N].sux[subj] + output[1:length(output)] = reorderval(- m.solutions[attr.N].sux[subj], D) elseif (mask & boundflag_cone) != 0 - output[1:length(output)] = m.solutions[attr.N].snx[subj] + output[1:length(output)] = reorderval(m.solutions[attr.N].snx[subj], D) else error("Dual value available for this constraint") end else if mask & boundflag_lower != 0 && mask & boundflag_upper != 0 - output[1:length(output)] = m.solutions[attr.N].sux[subj] - m.solutions[attr.N].slx[subj] + output[1:length(output)] = reorderval(m.solutions[attr.N].sux[subj] - m.solutions[attr.N].slx[subj], D) elseif (mask & boundflag_lower) != 0 - output[1:length(output)] = - m.solutions[attr.N].slx[subj] + output[1:length(output)] = reorderval(- m.solutions[attr.N].slx[subj], D) elseif (mask & boundflag_upper) != 0 - output[1:length(output)] = m.solutions[attr.N].sux[subj] + output[1:length(output)] = reorderval(m.solutions[attr.N].sux[subj], D) elseif (mask & boundflag_cone) != 0 - output[1:length(output)] = - m.solutions[attr.N].snx[subj] + output[1:length(output)] = reorderval(- m.solutions[attr.N].snx[subj], D) else error("Dual value available for this constraint") end @@ -444,11 +442,11 @@ function MOI.get!( elseif m.c_block_slack[cid] > 0 # qcone slack xid = m.c_block_slack[cid] xsubj = getindexes(m.x_block, xid) - output[1:length(output)] = m.solutions[attr.N].snx[xsubj] + output[1:length(output)] = reorderval(m.solutions[attr.N].snx[xsubj], getconeset(m, cid)) else # psd slack whichsol = getsolcode(m,attr.N) xid = - m.c_block_slack[cid] - output[1:length(output)] = sympackedLtoU(getbarsj(m.task,whichsol,Int32(xid))) + output[1:length(output)] = reorderval(getbarsj(m.task,whichsol,Int32(xid)), MOI.PositiveSemidefiniteConeTriangle) end else if m.c_block_slack[cid] == 0 # no slack @@ -456,11 +454,11 @@ function MOI.get!( elseif m.c_block_slack[cid] > 0 # qcone slack xid = m.c_block_slack[cid] subj = getindexes(m.x_block, xid) - output[1:length(output)] = - m.solutions[attr.N].snx[subj] + output[1:length(output)] = reorderval(- m.solutions[attr.N].snx[subj], getconeset(m, cid)) else # psd slack whichsol = getsolcode(m,attr.N) xid = - m.c_block_slack[cid] - output[1:length(output)] = sympackedLtoU(- getbarsj(m.task,whichsol,Int32(xid))) + output[1:length(output)] = reorderval(- getbarsj(m.task,whichsol,Int32(xid)), MOI.PositiveSemidefiniteConeTriangle) end end end diff --git a/src/constraint.jl b/src/constraint.jl index 9abbdc1..0c41555 100644 --- a/src/constraint.jl +++ b/src/constraint.jl @@ -60,15 +60,16 @@ function MOI.addconstraint!( conid = allocateconstraints(m,N) addlhsblock!(m, conid, - axb.outputindex, + orderidx(axb.outputindex, dom), axb.variables, axb.coefficients) conidxs = getindexes(m.c_block,conid) - m.c_constant[conidxs] = axb.constant + constant = orderval(axb.constant, dom) + m.c_constant[conidxs] = constant m.c_block_slack[conid] - addbound!(m,conid,conidxs,axb.constant,dom) + addbound!(m,conid,conidxs,constant,dom) conref = MOI.ConstraintIndex{MOI.VectorAffineFunction{Float64},D}(UInt64(conid) << 1) select(m.constrmap,MOI.VectorAffineFunction{Float64},D)[conref.value] = conid @@ -179,6 +180,20 @@ is_positivesemidefinite_set(dom) = false is_conic_set(dom :: VectorCone) = true is_conic_set(dom) = false +orderidx(idx, s) = idx +expmap(i) = 4 - i +function orderidx(idx, s::MOI.ExponentialCone) + expmap.(idx) +end + +orderval(val, s) = val +orderval(val, s::MOI.ExponentialCone) = val[3:-1:1] +orderval(val, s::MOI.PositiveSemidefiniteConeTriangle) = sympackedUtoL(val, s.dimension) + +reorderval(val, s) = val +reorderval(val, s::Type{MOI.ExponentialCone}) = val[3:-1:1] +reorderval(val, s::Type{MOI.PositiveSemidefiniteConeTriangle}) = sympackedLtoU(val) + addvarconstr(m :: MosekModel, subj :: Vector{Int}, dom :: MOI.Reals) = nothing function addvarconstr(m :: MosekModel, subj :: Vector{Int}, dom :: MOI.Zeros) bnd = zeros(Float64,length(subj)) @@ -231,6 +246,18 @@ end abstractset2ct(dom::MOI.SecondOrderCone) = MSK_CT_QUAD abstractset2ct(dom::MOI.RotatedSecondOrderCone) = MSK_CT_RQUAD +abstractset2ct(dom::MOI.ExponentialCone) = MSK_CT_PEXP +function ct2abstractset(ct::Mosek.Conetype) + if ct == MSK_CT_QUAD + MOI.SecondOrderCone + elseif ct == MSK_CT_RQUAD + MOI.RotatedSecondOrderCone + else + @assert ct == MSK_CT_PEXP + MOI.ExponentialCone + end +end +getconeset(m::MosekModel, cid) = ct2abstractset(getconeinfo(m.task, m.c_coneid[cid])[1]) function MOI.addconstraint!( m :: MosekModel, xs :: MOI.SingleVariable, @@ -264,7 +291,7 @@ function MOI.addconstraint!(m :: MosekModel, xs :: MOI.VectorOfVariables, dom :: D) where { D <: PositiveSemidefiniteCone } N = dom.dimension - vars = sympackedUtoL(xs.variables, N) + vars = orderval(xs.variables, dom) subj = Vector{Int}(length(vars)) for i in 1:length(subj) getindexes(m.x_block, ref2id(vars[i]),subj,i) @@ -342,6 +369,7 @@ function MOI.addconstraint!{D <: MOI.AbstractSet}(m :: MosekModel, xs :: MOI.Vec for i in 1:length(subj) getindexes(m.x_block, ref2id(xs.variables[i]),subj,i) end + subj = orderval(subj, dom) mask = domain_type_mask(dom) if any(mask .& m.x_boundflags[subj[1]] .> 0) diff --git a/test/runtests.jl b/test/runtests.jl index ceec6e8..18acbe4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,7 +7,7 @@ const MOIT = MathOptInterfaceTests const solver = () -> MosekInstance(QUIET = true) const config = MOIT.TestConfig(1e-7, 1e-7, true, false, true, true) -const configgeomean = MOIT.TestConfig(1e-4, 1e-4, true, false, true, true) +const configlowtol = MOIT.TestConfig(1e-4, 1e-4, true, false, true, true) @testset "Continuous linear problems" begin # linear11 is failing because the following are not implemented: @@ -24,12 +24,13 @@ end @testset "Continuous conic problems" begin # lin1 and soc1 are failing because ListOfConstraints is not implemented # sdp2 is failing because MOI.get(instance, MOI.ConstraintPrimal(), c1) returns -10 instead of 0 - MOIT.contconictest(solver, config, ["lin1v", "lin1f", "soc1", "geomean", "exp", "sdp2", "logdet"]) - MOIT.geomeantest(solver, configgeomean) + MOIT.contconictest(solver, config, ["lin1v", "lin1f", "soc1", "geomean", "exp", "sdp2"]) + MOIT.exptest(solver, configlowtol) + MOIT.geomeantest(solver, configlowtol) end @testset "Mixed-integer linear problems" begin MOIT.intlineartest(solver, config, ["int2"]) end -include("test_jump.jl") +#include("test_jump.jl")