From 860d1eb9c15161c3b423b12b6bde91abb3e67449 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 20 Mar 2025 15:57:59 +1300 Subject: [PATCH 1/2] Fix MOI.ListOfVariableIndices --- src/constraint.jl | 17 +++++------------ src/variable.jl | 5 ++--- test/runtests.jl | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/constraint.jl b/src/constraint.jl index f7f1e71..12c4fff 100644 --- a/src/constraint.jl +++ b/src/constraint.jl @@ -794,8 +794,8 @@ end function MOI.add_constrained_variables( m::Optimizer, - dom::MOI.PositiveSemidefiniteConeTriangle, -) + dom::S, +) where {S<:MOI.PositiveSemidefiniteConeTriangle} N = MOI.side_dimension(dom) if N < 1 error( @@ -803,18 +803,11 @@ function MOI.add_constrained_variables( "smaller than the minimum dimension 1.", ) end - Mosek.appendbarvars(m.task, [Int32(N)]) + Mosek.appendbarvars(m.task, Int32[N]) push!(m.sd_dim, N) id = length(m.sd_dim) - vis = - [new_variable_index(m, MatrixIndex(id, i, j)) for i in 1:N for j in 1:i] - con_idx = MOI.ConstraintIndex{ - MOI.VectorOfVariables, - MOI.PositiveSemidefiniteConeTriangle, - }( - id, - ) - return vis, con_idx + x = [new_variable_index(m, MatrixIndex(id, i, j)) for i in 1:N for j in 1:i] + return x, MOI.ConstraintIndex{MOI.VectorOfVariables,S}(id) end ## Get ######################################################################## diff --git a/src/variable.jl b/src/variable.jl index 058ae18..50aabd5 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -236,7 +236,7 @@ end ############################################################################### function MOI.is_valid(model::Optimizer, vi::MOI.VariableIndex) - return allocated(model.x_block, ref2id(vi)) + return get(model.x_block.size, vi.value, 0) == 1 end function delete_vector_of_variables_constraint( @@ -287,8 +287,7 @@ end MOI.get(m::Optimizer, ::MOI.NumberOfVariables) = sum(m.x_block.size) function MOI.get(m::Optimizer, ::MOI.ListOfVariableIndices) - ids = allocatedlist(m.x_block) - return MOI.VariableIndex[MOI.VariableIndex(vid) for vid in ids] + return MOI.VariableIndex.(findall(isone, m.x_block.size)) end function MOI.get(m::Optimizer, ::MOI.ListOfVariableAttributesSet) diff --git a/test/runtests.jl b/test/runtests.jl index cf8984f..9c6f572 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -560,6 +560,52 @@ function test_issue_134() return end +function test_add_constrained_variables() + model = Mosek.Optimizer() + # Add a scalar + x = MOI.add_variable(model) + @test MOI.get(model, MOI.ListOfVariableIndices()) == [x] + @test MOI.is_valid(model, x) + @test MOI.get(model, MOI.NumberOfVariables()) == 1 + # Add a PSD matrix + set = MOI.PositiveSemidefiniteConeTriangle(2) + X, _ = MOI.add_constrained_variables(model, set) + @test MOI.get(model, MOI.ListOfVariableIndices()) == [x; X] + @test all(MOI.is_valid.(model, [x; X])) + @test MOI.get(model, MOI.NumberOfVariables()) == 4 + # Add and delete a scalar + y = MOI.add_variable(model) + @test MOI.get(model, MOI.ListOfVariableIndices()) == [x; X; y] + @test all(MOI.is_valid.(model, [x; X; y])) + @test MOI.get(model, MOI.NumberOfVariables()) == 5 + MOI.delete(model, y) + @test !MOI.is_valid(model, y) + @test MOI.get(model, MOI.ListOfVariableIndices()) == [x; X] + @test all(MOI.is_valid.(model, [x; X])) + @test MOI.get(model, MOI.NumberOfVariables()) == 4 + # Add and delete another scalar + z = MOI.add_variable(model) + @test MOI.get(model, MOI.ListOfVariableIndices()) == [x; X; z] + @test all(MOI.is_valid.(model, [x; X])) + @test MOI.is_valid(model, z) + @test MOI.get(model, MOI.NumberOfVariables()) == 5 + MOI.delete(model, z) + @test !MOI.is_valid(model, y) + @test !MOI.is_valid(model, z) + @test MOI.get(model, MOI.ListOfVariableIndices()) == [x; X] + @test all(MOI.is_valid.(model, [x; X])) + @test MOI.get(model, MOI.NumberOfVariables()) == 4 + MOI.delete(model, x) + @test !MOI.is_valid(model, x) + @test !MOI.is_valid(model, y) + @test !MOI.is_valid(model, z) + @test MOI.get(model, MOI.ListOfVariableIndices()) == X + @test all(MOI.is_valid.(model, X)) + @test MOI.get(model, MOI.NumberOfVariables()) == 3 + @test_throws(MOI.DeleteNotAllowed, MOI.delete(model, X[1])) + return +end + end # module TestMosekTools.runtests() From a4629d29b526a3275ad31e8d377343d9dd23b3a6 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 20 Mar 2025 16:14:54 +1300 Subject: [PATCH 2/2] Update --- src/objective.jl | 17 ++++++++--------- src/variable.jl | 4 +++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/objective.jl b/src/objective.jl index 9b10e89..75bf20c 100644 --- a/src/objective.jl +++ b/src/objective.jl @@ -24,15 +24,14 @@ function MOI.get( msg = "Cannot get objective if it contains the contribution of the entry of a PSD variable." throw(MOI.GetAttributeNotAllowed(attr, msg)) end - cis = MOI.get(m, MOI.ListOfVariableIndices()) - cols = columns(m, cis).values - coeffs = Mosek.getclist(m.task, cols) - constant = Mosek.getcfix(m.task) - @assert length(coeffs) == length(cis) - terms = MOI.ScalarAffineTerm{Float64}[ - MOI.ScalarAffineTerm(coeffs[i], cis[i]) for i in 1:length(cis) - ] - return MOI.ScalarAffineFunction(terms, constant) + # List of scalar variables only. Exclude matrix variables and those deleted. + xs = [MOI.VariableIndex(i) for (i, x) in enumerate(m.x_sd) if x.matrix == 0] + coeffs = Mosek.getclist(m.task, columns(m, xs).values) + @assert length(coeffs) == length(xs) + return MOI.ScalarAffineFunction{Float64}( + MOI.ScalarAffineTerm{Float64}.(coeffs, xs), + Mosek.getcfix(m.task), + ) end function MOI.supports( diff --git a/src/variable.jl b/src/variable.jl index 50aabd5..d21894c 100644 --- a/src/variable.jl +++ b/src/variable.jl @@ -287,7 +287,9 @@ end MOI.get(m::Optimizer, ::MOI.NumberOfVariables) = sum(m.x_block.size) function MOI.get(m::Optimizer, ::MOI.ListOfVariableIndices) - return MOI.VariableIndex.(findall(isone, m.x_block.size)) + return MOI.VariableIndex[ + MOI.VariableIndex(i) for (i, x) in enumerate(m.x_sd) if x.matrix >= 0 + ] end function MOI.get(m::Optimizer, ::MOI.ListOfVariableAttributesSet)