Skip to content

Conversation

@araujoms
Copy link
Contributor

@araujoms araujoms commented May 26, 2023

This adds the Hermitian bridge, which seems to do its job, but then the code dies when it reaches optimize! with the error "MathOptInterface.VectorAffineFunction{ComplexF64}-in-SeDuMi.ScaledPSDCone constraint is not supported by the model."

I suppose I need to edit OptimizerCache to tell MOI that this is actually supported, but I don't know how.

Closes #23

@araujoms
Copy link
Contributor Author

Sorry about the delay. Now the basic solving is working. Two problems remain: I can't figure out how to get extraction of dual variables to work, and the MOI tests are failing. The test failures seem to be due to MOI assuming that the raw solution returned by the solver is always real. This is not the case with SeDuMi, so if I understood it correctly the fix should be done there.

@odow
Copy link
Member

odow commented Sep 26, 2024

I'm not in a position to competently review this because I don't have MATLAB to test.

@odow odow requested a review from blegat September 26, 2024 03:20
@araujoms
Copy link
Contributor Author

I've made some progress in returning the dual variables; at least now the algorithm is in place, the remaining issue is calling it correctly. As you can see in lines 253-254, it works correctly if I manually switch between asking for the dual variables for the real and complex cones, but not both at the same time.

Also, I'm confused about the purpose of the function MOI.Bridges.inverse_map_function. Shouldn't it just be the same as MOI.Bridges.adjoint_map_function?

@araujoms
Copy link
Contributor Author

@blegat can you help me here?

@blegat
Copy link
Member

blegat commented Apr 15, 2025

Thanks for the reminder, I'll take a look

@blegat
Copy link
Member

blegat commented Apr 15, 2025

Maybe it's easier to instead add a bridge from MOI.VectorAffineFunction{T}-in-MOI.HermitianPositiveSemidefiniteConeTriangle to MOI.VectorAffineFunction{Complex{T}}-in-MOI.HermitianPositiveSemidefiniteConeTriangle, MOI.VectorAffineFunction{T}

@blegat
Copy link
Member

blegat commented Apr 15, 2025

@araujoms Can you try removing ScaledHermitianPSDConeBridge and replacing it with jump-dev/MathOptInterface.jl#2724 ?

@araujoms
Copy link
Contributor Author

araujoms commented Apr 15, 2025

I tried, got a bunch of errors. Why, though? Is this to get the MOI tests to pass? Solving was working correctly before, the part that was missing was recovering dual variables.

What I did is removing everything related to ScaledHermitianPSDConeBridge, and replacing the function that returns the list of nonstandard bridges with

function MOI.get(::Optimizer, ::MOI.Bridges.ListOfNonstandardBridges)
    return Type[
        ScaledPSDConeBridge{Float64},
        MOI.Bridges.Constraint.HermitianToComplexSymmetricBridge{Float64},
    ]
end

@blegat
Copy link
Member

blegat commented Apr 15, 2025

Why, though?

I prefer keeping simple bridges that do just one transformation rather than complicated bridges that mixes several ones. Especially when you need to figure out what's the adjoint of the inverse of the adjoint of the combination of several transformations. Here one of the two transformations I'm mentioning is the bridge from the MOI set to the SeDuMi set which is solver-specific and the other transformation is the one of jump-dev/MathOptInterface.jl#2724.
That PR is still a work in progress. Just pushed some fixes, only the adjoint and inverse adjoint are missing now

@blegat
Copy link
Member

blegat commented Apr 15, 2025

I have implemented the adjoint, can you try now ?

@araujoms
Copy link
Contributor Author

Sure. Same error as before:

ERROR: MethodError: no method matching promote_operation(::typeof(*), ::Type{Float64}, ::Type{Float64}, ::Type{MathOptInterface.ScalarAffineFunction{ComplexF64}})
The function `promote_operation` exists, but no method is defined for this combination of argument types.

I don't understand how is your new bridge supposed to work, though. ScaledHermitianPSDConeBridge mapped HermitianPositiveSemidefiniteConeTriangle to ScaledPSDCone, but your bridge is mapping it to PositiveSemidefiniteConeTriangle.

@blegat
Copy link
Member

blegat commented Apr 15, 2025

Yes but then ScaledPSDConeBridge can map VAF{Complex{Float64}}-in-PositiveSemidefiniteConeTriangle to VAF{Complex{Float64}}-in-ScaledPSDCone.

@blegat
Copy link
Member

blegat commented Apr 15, 2025

Ok I fixed that error on the MOI PR. I suspect we may still need to fix ScaledPSDConeBridge so that it works with a function of complex coefficients

@araujoms
Copy link
Contributor Author

Now it doesn't produce any errors, but it doesn't use SeDuMi's complex PSD cone, but the real one:

 * Supported objective: MOI.ScalarAffineFunction{Float64}
 * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.Zeros
 * Unsupported constraint: MOI.VectorOfVariables-in-MOI.HermitianPositiveSemidefiniteConeTriangle
 |  bridged by:
 |   MOIB.Constraint.HermitianToSymmetricPSDBridge{Float64, MOI.VectorAffineFunction{Float64}, MOI.VectorOfVariables}
 |  may introduce:
 |   * Unsupported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.PositiveSemidefiniteConeTriangle
 |   |  bridged by:
 |   |   SeDuMi.ScaledPSDConeBridge{Float64, MOI.VectorAffineFunction{Float64}}
 |   |  may introduce:
 |   |   * Supported constraint: MOI.VectorAffineFunction{Float64}-in-SeDuMi.ScaledPSDCone

In order for ScaledPSDConeBridge to accept complex numbers, perhaps we need to change something here:

struct ScaledPSDConeBridge{T,G} <: MOI.Bridges.Constraint.SetMapBridge{
    T,
    ScaledPSDCone,
    MOI.PositiveSemidefiniteConeTriangle,
    MOI.VectorAffineFunction{T},
    G,
}
    constraint::MOI.ConstraintIndex{MOI.VectorAffineFunction{T},ScaledPSDCone}
end

Is T somehow restricted to be real by MOI?

function MOI.get(::Optimizer, ::MOI.Bridges.ListOfNonstandardBridges)
return Type[ScaledPSDConeBridge{Float64}]
return Type[
ScaledPSDConeBridge{Float64},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may need to add ScaledPSDConeBridge{Complex{Float64}} here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No luck, still get the same error as before.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you push your work in progress that gets this error as a commit to this branch ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, done

@odow
Copy link
Member

odow commented Apr 23, 2025

I think the problem is that it expects optimizer.sol.x to be real, but it is in general complex with SeDuMi.

MOI doesn't care what the internal type is. You just need to make sure that the return types from MOI.get are what it expects.

@odow
Copy link
Member

odow commented Apr 23, 2025

p.s., I've asked MATLAB for a license, because it's virtually impossible for me to review this PR without CI.

Co-authored-by: Oscar Dowson <[email protected]>
@jump-dev jump-dev deleted a comment from araujoms Apr 23, 2025
@araujoms
Copy link
Contributor Author

araujoms commented Apr 24, 2025

That was it! MOI tests pass now. I only had to do the analogous change to querying the slack variables.

@blegat
Copy link
Member

blegat commented Apr 25, 2025

Awesome, the PR is still blocked by

@araujoms
Copy link
Contributor Author

araujoms commented May 4, 2025

Just tested with MOI 1.40, everything works fine.

# of the sets just listed above.

const ComplexAff = MOI.VectorAffineFunction{Complex{Float64}}
const RealAff = MOI.VectorAffineFunction{Float64}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these lines and use MOI.VectorAffineFunction{Float64} and MOI.VectorAffineFunction{ComplexF64} everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doesn't even compile if I do that. In any case this is Benoît's code, not mine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment above explaining why they are needed

@blegat
Copy link
Member

blegat commented May 6, 2025

Tests are passing

shell> git log HEAD^..HEAD
commit 637db910cc5a28f8d8fed0655cc184c86210ee2d (HEAD -> complex, araujoms/complex)
Author: Benoît Legat <[email protected]>
Date:   Tue May 6 08:47:27 2025 +0200

    Fix format

julia> versioninfo()
Julia Version 1.10.2
Commit bd47eca2c8a (2024-03-01 10:14 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 36 × Intel(R) Xeon(R) W-2295 CPU @ 3.00GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, cascadelake)
Threads: 1 default, 0 interactive, 1 GC (on 36 virtual cores)
Environment:
  JULIA_EDITOR = code
  JULIA_NUM_THREADS = 

julia> include("test/runtests.jl");
Precompiling SeDuMi
  1 dependency successfully precompiled in 2 seconds. 39 already precompiled.
Test Summary:              | Pass  Total  Time
Linear Programming example |    7      7  2.1s
Test Summary:                    | Pass  Total  Time
Semidefinite Programming example |   10     10  0.6s
>> SeDuMi 1.3.7 by AdvOL, 2005-2008 and Jos F. Sturm, 1998-2003.
Alg = 2: xz-corrector, Adaptive Step-Differentiation, theta = 0.250, beta = 0.500
eqs m = 1, order n = 3, dim = 9, blocks = 2
nnz(A) = 1 + 0, nnz(ADA) = 1, nnz(L) = 1
 it :     b*y       gap    delta  rate   t/tP*  t/tD*   feas cg cg  prec
  0 :            8.33E+00 0.000
  1 :   5.15E-01 1.60E+00 0.000 0.1923 0.9000 0.9000   1.46  1  1  7.6E-01
  2 :   9.95E-01 4.27E-02 0.000 0.0267 0.9900 0.9900   0.95  1  1  1.9E-02
  3 :   1.00E+00 4.38E-07 0.000 0.0000 1.0000 1.0000   1.00  1  1  1.6E-07
  4 :   1.00E+00 4.54E-14 0.000 0.0000 1.0000 1.0000   1.00  1  1  1.6E-14

iter seconds digits       c*x               b*y
  4      0.1  14.1  1.0000000000e+00  1.0000000000e+00
|Ax-b| =   5.4e-15, [Ay-c]_+ =   0.0E+00, |x|=  1.0e+00, |y|=  1.0e+00

Detailed timing (sec)
   Pre          IPM          Post
3.634E-02    5.408E-02    2.404E-03    
Max-norms: ||b||=1, ||c|| = 1,
Cholesky |add|=0, |skip| = 0, ||L.L|| = 1.
Test Summary: | Pass  Total  Time
test_complex  |    4      4  3.5s
Test Summary:        | Pass  Total  Time
test_complex_bridges |    4      4  3.5s
Test Summary: | Pass  Total  Time
test_options  |    1      1  0.0s
>> Warning: Rank deficient, rank = 1, tol =  4.615110e-14. 
> In sedumi (line 272)
 
>> Warning: Rank deficient, rank = 1, tol =  4.615110e-14. 
> In sedumi (line 272)
 
Test Summary: | Pass  Total     Time
test_runtests | 4070   4070  5m05.0s
Test Summary:    | Pass  Total  Time
test_solver_name |    1      1  0.0s

@blegat
Copy link
Member

blegat commented May 6, 2025

@araujoms Thanks a lot !!

@blegat blegat merged commit c4fd4ba into jump-dev:master May 6, 2025
1 check passed
@araujoms
Copy link
Contributor Author

araujoms commented May 6, 2025

Thank you! That was quite an odyssey.

@araujoms araujoms deleted the complex branch May 6, 2025 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Add support for complex interface

3 participants