Note that X
isn’t really a matrix. It’s a JuMP.Containers.SparseAxisArray
which in some cases acts like a matrix, but is more like a dictionary with keys.
One way to get a lower triangular matrix is:
@variable(model, X[1:n, 1:n], Symmetric)
Xl = LinearAlgebra.LowerTriangular(X)
But you’ll still run into the problem that @SteffenPL reports where JuMP cannot always multiply two matrices outside of the macros.
Here’s an example:
julia> model = Model()
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: NO_OPTIMIZER
Solver name: No optimizer attached.
julia> n = 3
3
julia> @variable(model, X[1:n, 1:n], Symmetric)
3×3 Symmetric{VariableRef, Matrix{VariableRef}}:
X[1,1] X[1,2] X[1,3]
X[1,2] X[2,2] X[2,3]
X[1,3] X[2,3] X[3,3]
julia> Xl = LinearAlgebra.LowerTriangular(X)
3×3 LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}}:
X[1,1] ⋅ ⋅
X[1,2] X[2,2] ⋅
X[1,3] X[2,3] X[3,3]
julia> X * Xl
ERROR: ArgumentError: Cannot set a non-diagonal index in a symmetric matrix
Stacktrace:
[1] setindex!(A::Symmetric{QuadExpr, Matrix{QuadExpr}}, v::VariableRef, i::Int64, j::Int64)
@ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/symmetric.jl:225
[2] setindex!
@ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/triangular.jl:257 [inlined]
[3] _setindex!
@ ./abstractarray.jl:1297 [inlined]
[4] setindex!
@ ./abstractarray.jl:1267 [inlined]
[5] copyto_unaliased!(deststyle::IndexCartesian, dest::LowerTriangular{QuadExpr, Symmetric{QuadExpr, Matrix{QuadExpr}}}, srcstyle::IndexCartesian, src::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ Base ./abstractarray.jl:984
[6] copyto!
@ ./abstractarray.jl:950 [inlined]
[7] copyto_axcheck!(dest::LowerTriangular{QuadExpr, Symmetric{QuadExpr, Matrix{QuadExpr}}}, src::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ Base ./abstractarray.jl:1056
[8] AbstractMatrix{QuadExpr}(A::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ Base ./array.jl:541
[9] AbstractArray
@ ./boot.jl:475 [inlined]
[10] convert
@ ./abstractarray.jl:15 [inlined]
[11] *(A::Symmetric{VariableRef, Matrix{VariableRef}}, B::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/triangular.jl:1699
[12] top-level scope
@ REPL[12]:1
julia> Xl * X
ERROR: ArgumentError: Cannot set a non-diagonal index in a symmetric matrix
Stacktrace:
[1] setindex!(A::Symmetric{QuadExpr, Matrix{QuadExpr}}, v::VariableRef, i::Int64, j::Int64)
@ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/symmetric.jl:225
[2] setindex!
@ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/triangular.jl:257 [inlined]
[3] _setindex!
@ ./abstractarray.jl:1297 [inlined]
[4] setindex!
@ ./abstractarray.jl:1267 [inlined]
[5] copyto_unaliased!(deststyle::IndexCartesian, dest::LowerTriangular{QuadExpr, Symmetric{QuadExpr, Matrix{QuadExpr}}}, srcstyle::IndexCartesian, src::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ Base ./abstractarray.jl:984
[6] copyto!
@ ./abstractarray.jl:950 [inlined]
[7] copyto_axcheck!(dest::LowerTriangular{QuadExpr, Symmetric{QuadExpr, Matrix{QuadExpr}}}, src::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ Base ./abstractarray.jl:1056
[8] AbstractMatrix{QuadExpr}(A::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}})
@ Base ./array.jl:541
[9] AbstractArray
@ ./boot.jl:475 [inlined]
[10] convert
@ ./abstractarray.jl:15 [inlined]
[11] *(A::LowerTriangular{VariableRef, Symmetric{VariableRef, Matrix{VariableRef}}}, B::Symmetric{VariableRef, Matrix{VariableRef}})
@ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/triangular.jl:1657
[12] top-level scope
@ REPL[13]:1
julia> @expression(model, Xl * X)
3×3 Matrix{QuadExpr}:
X[1,1]² … X[1,1]*X[1,3]
X[1,2]*X[1,1] + X[2,2]*X[1,2] X[1,2]*X[1,3] + X[2,2]*X[2,3]
X[1,3]*X[1,1] + X[2,3]*X[1,2] + X[3,3]*X[1,3] X[1,3]² + X[2,3]² + X[3,3]²