diff --git a/src/solvers.jl b/src/solvers.jl index 819361a109b..dbb28ef6a83 100644 --- a/src/solvers.jl +++ b/src/solvers.jl @@ -992,8 +992,12 @@ function conicdata(m::Model) for i in 1:n, j in 1:(i-1) collect_expr!(m, tmprow, con.terms[i,j] - con.terms[j,i]) nnz = tmprow.nnz - # if the symmetry-enforcing row is empty, just drop it - if nnz == 0 + # if the symmetry-enforcing row is empty or has only tiny coefficients due to unintended numerical asymmetry, drop it + largestabs = 0.0 + for k in 1:nnz + largestabs = max(largestabs,abs(tmpelts[tmpnzidx[k]])) + end + if largestabs < 1e-10 numDroppedSym += 1 continue end @@ -1005,7 +1009,9 @@ function conicdata(m::Model) append!(V, tmpelts[indices]) b[c] = 0 end - push!(con_cones, (:Zero, sym_start:c)) + if c >= sym_start + push!(con_cones, (:Zero, sym_start:c)) + end constr_dual_map[numLinRows + numBounds + numNormRows + length(m.sdpconstr) + sdpidx] = collect(sym_start:c) @assert length(syms) == length(sym_start:c) else diff --git a/test/sdp.jl b/test/sdp.jl index fd2b8350f14..2b8b2687c08 100644 --- a/test/sdp.jl +++ b/test/sdp.jl @@ -173,13 +173,14 @@ ispsd(x::JuMP.JuMPArray) = ispsd(x.innerArray) @test isapprox(getobjectivevalue(m), 1.293, atol=1e-2) end - @testset "Trivial symmetry constraints are removed (#766)" begin + @testset "Trivial symmetry constraints are removed (#766, #972)" begin q = 2 m = 3 angles1 = linspace(3*pi/4, pi, m) angles2 = linspace(0, -pi/2, m) - V = [3.*cos(angles1)' 1.5.*cos(angles2)'; - 3.*sin(angles1)' 1.5.*sin(angles2)'] + V = [3.*cos.(angles1)' 1.5.*cos.(angles2)'; + 3.*sin.(angles1)' 1.5.*sin.(angles2)'] + V[abs.(V) .< 1e-10] = 0.0 p = 2*m n = 100 @@ -193,10 +194,11 @@ ispsd(x::JuMP.JuMPArray) = ispsd(x.innerArray) end f, A, b, var_cones, con_cones = JuMP.conicdata(mod) @test length(f) == 8 - @test size(A) == (23,8) - @test length(b) == 23 + @test size(A) == (21,8) + @test minimum(abs.(nonzeros(A))) > 0.01 + @test length(b) == 21 @test var_cones == [(:Free,[1,2,3,4,5,6,7,8])] - @test con_cones == [(:NonNeg,[1]),(:NonPos,[2,3,4,5,6,7,8,9]),(:SDP,10:15),(:Zero,16:16),(:SDP,17:22),(:Zero,23:23)] + @test con_cones == [(:NonNeg,[1]),(:NonPos,[2,3,4,5,6,7,8,9]),(:SDP,10:15),(:SDP,16:21)] end # Adapt SDP atom tests from Convex.jl: