Skip to content

Commit

Permalink
Improve printing of symmetric matrices when used in constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed Jun 4, 2024
1 parent 886a652 commit f11b205
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 6 deletions.
6 changes: 3 additions & 3 deletions docs/src/manual/constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -1462,17 +1462,17 @@ julia> Z = [X[1, 1] X[1, 2]; X[1, 2] X[2, 2]]
julia> @constraint(model, LinearAlgebra.Symmetric(Z) >= 0, PSDCone())
[X[1,1] X[1,2]
X[1,2] X[2,2]] ∈ PSDCone()
X[2,2]] ∈ PSDCone()
```

Note that the lower triangular entries are ignored even if they are
different so use it with caution:
```jldoctest con_psd
julia> @constraint(model, LinearAlgebra.Symmetric(X) >= 0, PSDCone())
[X[1,1] X[1,2]
X[1,2] X[2,2]] ∈ PSDCone()
X[2,2]] ∈ PSDCone()
```
(Note the `(2, 1)` element of the constraint is `X[1,2]`, not `X[2,1]`.)
(Note that no error is thrown, even though `X` is not symmetric.)

## Complementarity constraints

Expand Down
15 changes: 15 additions & 0 deletions src/print.jl
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,8 @@ function function_string(
end
if A isa LinearAlgebra.Symmetric && i > j
line *= "\\cdot"
elseif A isa LinearAlgebra.UpperTriangular && i > j
line *= "\\cdot"
else
line *= function_string(mode, A[i, j])
end
Expand All @@ -923,6 +925,19 @@ function function_string(mode, constraint::AbstractConstraint)
return function_string(mode, f)
end

# A special case for symmetric matrix constraints. Since the shape is
# SymmetricMatrixShape, we know that MOI has been passed the upper triangle of
# the matrix. We can make this clearer to users by printing the
# LinearAlgebra.UpperTriangular. There shouldn't be any cases in which the
# constraint function becomes ambiguous.
function function_string(
mode,
constraint::VectorConstraint{F,S,SymmetricMatrixShape},
) where {F,S}
f = reshape_vector(jump_function(constraint), shape(constraint))
return function_string(mode, LinearAlgebra.UpperTriangular(f))
end

function function_string(mode::MIME, p::NonlinearExpression)
nlp = nonlinear_model(p.model)::MOI.Nonlinear.Model
expr = nlp[index(p)]
Expand Down
4 changes: 2 additions & 2 deletions src/sd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ julia> a = [x 2x; 2x x];
julia> b = [1 2; 2 4];
julia> cref = @constraint(model, Symmetric(a - b) in PSDCone())
[x - 1 2 x - 2
2 x - 2 x - 4] ∈ PSDCone()
[x - 1 2 x - 2
x - 4] ∈ PSDCone()
julia> jump_function(constraint_object(cref))
3-element Vector{AffExpr}:
Expand Down
18 changes: 17 additions & 1 deletion test/test_print.jl
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ Subject to
con : a + b - 10 c + c1 - 2 x $le 1
a*b $le 2
[a b
b x] $inset $(PSDCone())
x] $inset $(PSDCone())
[a, b, c] $inset $(MOI.PositiveSemidefiniteConeTriangle(2))
[a b
c x] $inset $(PSDCone())
Expand Down Expand Up @@ -1094,4 +1094,20 @@ function test_invalid_references()
return
end

function test_symmetric_constraint()
model = Model()
@variable(model, x[1:2, 1:2], Symmetric)
@test function_string(MIME("text/plain"), x) ==
"[x[1,1] x[1,2]\n x[1,2] x[2,2]]"
@test function_string(MIME("text/latex"), x) ==
"\\begin{bmatrix}\nx_{1,1} & x_{1,2}\\\\\n\\cdot & x_{2,2}\\\\\n\\end{bmatrix}"
c = @constraint(model, x in PSDCone())
o = constraint_object(c)
@test function_string(MIME("text/plain"), o) ==
"[x[1,1] x[1,2]\n ⋅ x[2,2]]"
@test function_string(MIME("text/latex"), o) ==
"\\begin{bmatrix}\nx_{1,1} & x_{1,2}\\\\\n\\cdot & x_{2,2}\\\\\n\\end{bmatrix}"
return
end

end # TestPrint

0 comments on commit f11b205

Please sign in to comment.