Seeking low rank solution for two PSD matrices via `SDPLR.jl` in `JuMP`

I am trying the SDPLR.jl solver in JuMP for finding low-rank solutions to SDPs and it is working quite nicely when the underlying semidefinite optimization problem has only one PSD variable X. How do I apply SDPLR.jl in JuMP when I have two SDP matrices X and Y, where I want to seek a rank 1 solution for X and say rank 2 solution on Y. The README.md file for SDPLR.jl is not super clear in this regard of this can be done.

I will appreciate any tips/suggestions on this. If there are other SDP solvers that gives sparse/low-rank solutions to SDPs in JuMP ecosystem, please let me know.

This is a question for @blegat. He’s been working on the low-rank stuff.

Have you tried something along these lines?

using LinearAlgebra, JuMP, SDPLR, MathOptInterface
const MOI = MathOptInterface

nx = 4   # size of X
ny = 6   # size of Y

model = Model(SDPLR.Optimizer)

@variable(model, X[1:nx, 1:nx], PSD)
@variable(model, Y[1:ny, 1:ny], PSD)

# objective and constraints ...

set_attribute(model, "maxrank", function(m, n)
    if n == nx
        return 1   # rank-1 factor for X
    elseif n == ny
        return 2   # rank-2 factor for Y
    else
        return SDPLR.default_maxrank(m, n)   # fallback
    end
end)

optimize!(model)

Fx = MOI.get(model, SDPLR.Factor(), VariableInSetRef(X))  # nx×1
Fy = MOI.get(model, SDPLR.Factor(), VariableInSetRef(Y))  # ny×2 or paste code here

            ***   SDPLR 1.03-beta   ***

===================================================
 major   minor        val        infeas      time  
---------------------------------------------------
    1        0   0.00000000e+00  0.0e+00       0
===================================================

DIMACS error measures: 0.00e+00 0.00e+00 0.00e+00 -0.00e+00 0.00e+00 0.00e+00


julia> Fx = MOI.get(model, SDPLR.Factor(), VariableInSetRef(X))  # nx×1
4×1 Matrix{Float64}:
 -0.5556374349255623
 -0.20338580709894138
 -0.050108647317640864
 -0.25648261076643797

julia> Fy = MOI.get(model, SDPLR.Factor(), VariableInSetRef(Y))  # ny×2
6×2 Matrix{Float64}:
 -0.318264   -0.482569
 -0.413709    0.709417
  0.264882    0.686019
 -0.125805   -0.170905
  0.0918272   0.0715626
 -0.650191   -0.139925

Thanks for your response. In my test case, the size of the matrices could be the same, i.e., nx can be equal to ny, so it would be great if there is a way to seek low rank solution to matrices of same size.

ny = 4 in the example doesn’t behave as expected?

Good questions. Indeed if they have the same dimension, setting a function probably doesn’t work. My plan is to define variable attributes for this in LowRankOpt.jl that would then behave uniformly across Burer-Motneiro solvers such as SDPLR and SDPLRPlus.
At the moment, if you use SDPLRPlus using the LowRankOpt interface, you can use the ranks optimizer attribute:

It is not ideal since you’re giving a list of ranks that should be of length equal to the number of PSD variables which is why the goal is to have variable attributes instead.
This will be discussed during my talk at JuMP-dev 2026 and hopefully there will be variable attributes by then :slight_smile:

Thanks for your response. When nx = ny then the code will just impose rank 2 on both, I think.

Thanks @blegat , for now I will try the LowRankOpt.jl approach that you suggested. Looking forward to your talk at JuMP-dev!