-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add complex psd cone #301
base: master
Are you sure you want to change the base?
add complex psd cone #301
Conversation
@araujoms you can also benchmark this before merging by compiling and using SCS_jll locally. If you need any pointers on how to do this let me know |
The problem is that SCS.jl can't access the new cone, neither through JuMP nor through the low-level interface. That's the part that I still need to write. |
How do I use the binaries I compiled locally, though? I tried simply replacing the files |
For sure you need to write the interface code in julia, we'll also need to rethink how we interact with the solver in our C-wrapper. @blegat can maybe help you with advertising the complex functionality through MOI apis ;) To compile jll locally you can either override the library manually, or compile SCS_jll through BinaryBuilder and deploy locally. Both are described in details here: I don't actually recommend the first option (due to compiler options and linking expected by
|
Thanks! I did it manually in the end because life is too short to deal with BinaryBuilder. Your instructions were essential anyway so I could find out the compilations options that needed to be changed. (Btw since you have mastered the dark arts, perhaps you're interested in ressurrecting SDPAFamily? Someone needs to move it from In any case, I hacked together a bare Julia interface and did some benchmarking, via a simple SDP that computes the minimal eigenvalue of a random complex matrix. The blue line does it with the real psd cone, via the usual mapping |
…e might as well add it in the proper place
By no means I'm interested in hacking on some old C/C++ code to get it compiling :D
looking forward to it!
Looks great to me 🚀. What are the axes labels? |
Maybe there are some people who find C++ archaeology fun 🤷 Personally I find it about as fun as warts. Vertical axis is the time in milliseconds, horizontal axis is the dimension of the matrix. |
maybe some llms will do it some day for us :D |
My patience only lasted until 2^9. The ratio of the time taken with the real psd cone over the complex psd cone was using SCS
using SparseArrays
using LinearAlgebra
import Random
function extract_lower_triangle(C::AbstractMatrix{T}) where {T}
R = real(T)
is_complex = T <: Complex
d = size(C,1)
vec_dim = is_complex ? d^2 : div(d*(d+1),2)
c = Vector{R}(undef, vec_dim)
if is_complex
extract_lower_triangle_complex!(c, C, sqrt(R(2)))
else
extract_lower_triangle_real!(c, C, sqrt(R(2)))
end
return c
end
function extract_lower_triangle_real!(c, C, sqrt2)
d = size(C,1)
counter = 0
for j = 1:d
counter += 1
c[counter] = C[j,j]
for i = j+1:d
counter += 1
c[counter] = C[i,j]*sqrt2
end
end
end
function extract_lower_triangle_complex!(c, C, sqrt2)
d = size(C,1)
counter = 0
for j = 1:d
counter += 1
c[counter] = real(C[j,j])
for i = j+1:d
counter += 1
c[counter] = real(C[i,j])*sqrt2
counter += 1
c[counter] = imag(C[i,j])*sqrt2
end
end
end
function benchmark(::Type{T}, d) where {T}
Random.seed!(1337)
C = Hermitian(randn(complex(T), d, d))
if T <: Real
real_C = Hermitian([real(C) imag(C); -imag(C) real(C)])
return mineig_raw(real_C)
else
return mineig_raw(C)
end
end
function mineig_raw(C::AbstractMatrix{T}) where {T}
is_complex = T <: Complex
R = real(T)
d = size(C, 1)
c = extract_lower_triangle(C)
vec_dim = is_complex ? d^2 : div(d*(d+1), 2)
id_vec = sparse(extract_lower_triangle(T.(I(d))))
A = [id_vec'; -sparse(I, vec_dim, vec_dim)]
b = zeros(R, vec_dim + 1)
b[1] = 1
n = vec_dim
m = vec_dim + 1
z = 1
bu = Float64[]
bl = Float64[]
l = 0
ep = 0
ed = 0
q = Int[]
if is_complex
s = Int[]
cs = [d]
else
s = [d]
cs = Int[]
end
P = spzeros(n, n)
solver = SCS.DirectSolver
sol = scs_solve(solver, m, n, A, P, b, c, z, l, bu, bl, q, s, cs, ep, ed, Float64[], Float64[])
display(minimum(eigvals(Hermitian(C))))
display(sol.info.pobj)
return sol.info.solve_time
end run |
looks great! |
Awesome, thanks for doing this! I will take a look. |
Closes #290
In the end I didn't use Hypatia's indexing, but something that was close to what SCS was already doing in the real case.
You can test it via the following code:
I didn't do benchmarking because that's just painful in C. Once it's merged I can write the Julia interface and benchmark it.