# Error when constraining variable to be Hermitian PSD

**URL:** <https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223>\
**Category:** Optimization (Mathematical)\
**Tags:** jump, complex-numbers\
**Created:** [February 26, 2023, 9:21am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223 "2023-02-26T09:21:33Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [February 26, 2023, 9:21am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/1 "2023-02-26T09:21:33Z")

</div>

I’m writing an SDP for a traditional problem in quantum information, state discrimination. When I constrain the variables to real symmetric, it works. But the problem really needs them to be complex Hermitian. The code is

```julia
using JuMP
import LinearAlgebra
import Random
import SCS

function random_state(d)
	x = randn(ComplexF64, (d,d))
	y = x*adjoint(x)
	rho = Hermitian(y/tr(y))
	return rho
end
	
function discriminate(d,n)
    model = Model(SCS.Optimizer)
    rho = Array{ComplexF64}(undef,d, d, n)
    for i=1:n
    	rho[:,:,i] = random_state(d)
    end
	E = model[:E] = reshape(
           hcat([
               @variable(model, [1:d, 1:d] in PSDCone(), base_name = "E$(i)")
               for i in 1:n-1
           ]...),
           d, d, n-1,
       )
	lastE = I - sum(E[:,:,i] for i in 1:n-1)
	@constraint(model, lastE in PSDCone())
	obj = real(sum(dot(rho[:,:,i],E[:,:,i]) for i in 1:n-1)+dot(rho[:,:,n],lastE))/n
    @objective(model, Max, obj)
    optimize!(model)
    print(value(obj))
end	

```

When I change “PSDCone()” to “HermitianPSDCone()” I get the error “Unrecognized constraint building format.” Is this a bug? Is there a way to make it work?

A bit unrelated, but is there a more convenient way to declare a set of Hermitian variables? With YALMIP I can just do

```julia
E = sdpvar(d,d,n-1,'hermitian','complex');

```

which is much more concise and readable.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [February 26, 2023, 7:17pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/2 "2023-02-26T19:17:07Z")

</div>

I should improve the documentation, [Complex number support · JuMP](https://jump.dev/JuMP.jl/stable/manual/complex/#Hermitian-PSD-constraints), to explain that `H` needs to be explicitly marked as `Hermitian`. (See [[docs] clarify that matrix must be Hermitian by odow · Pull Request #3241 · jump-dev/JuMP.jl · GitHub](https://github.com/jump-dev/JuMP.jl/pull/3241))

Here’s how I would write your model:

```plaintext
using JuMP
import LinearAlgebra
import SCS

function random_state(d)
    x = randn(ComplexF64, (d, d))
    y = x * x'
    return LinearAlgebra.Hermitian(y / LinearAlgebra.tr(y))
end
    
function discriminate(d, n)
    model = Model(SCS.Optimizer)
    rho = [random_state(d) for i in 1:n]
    E = [
        @variable(model, [1:d, 1:d] in HermitianPSDCone(), base_name = "E$(i)")
        for i in 1:n-1
    ]
    lastE = LinearAlgebra.I - sum(E)
    @constraint(model, LinearAlgebra.Hermitian(lastE) in HermitianPSDCone())
    obj = real(
        sum(LinearAlgebra.dot(rho[i], E[i]) for i in 1:n-1) +
        LinearAlgebra.dot(rho[n], lastE)
    ) / n
    @objective(model, Max, obj)
    optimize!(model)
    return objective_value(model)
end

```

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [February 26, 2023, 10:18pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/3 "2023-02-26T22:18:02Z")

</div>

Thanks a lot! Something very weird happened, though. If instead of your version

```julia
	lastE = I - sum(E[i] for i in 1:n-1)
	@constraint(model, Hermitian(lastE) in HermitianPSDCone())

```

I write

```julia
	lastE = Hermitian(I - sum(E[i] for i in 1:n-1))
	@constraint(model, lastE in HermitianPSDCone())

```

I don’t get an error message either, but the SDP gives me the wrong result! Any idea what is going on?

And, since you’re improving the documentation anyway, perhaps it would be worth mentioning this much nicer way of declaring a set of Hermitian PSD variables that you wrote down?

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [February 26, 2023, 10:39pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/4 "2023-02-26T22:39:21Z")

</div>

Hmm. Let me take a look.

You could also write it like this, which is perhaps even simpler:

```julia
function discriminate(d, n)
    model = Model(SCS.Optimizer)
    set_silent(model)
    rho = [random_state(d) for i in 1:n]
    E = [@variable(model, [1:d, 1:d] in HermitianPSDCone()) for i in 1:n]
    @constraint(model, sum(E) .== LinearAlgebra.I)
    @objective(model, Max, real(LinearAlgebra.dot(rho, E)) / n)
    optimize!(model)
    return objective_value(model)
end

```

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [February 26, 2023, 11:07pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/5 "2023-02-26T23:07:48Z")

</div>

I’m aware of this formulation, it’s the most straightforward way to code state discrimination. I avoided it because it has unnecessary variables and constraints, and as such is slower and less precise

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [February 26, 2023, 11:11pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/6 "2023-02-26T23:11:05Z")

</div>

It looks like your incorrect case is a bug in JuMP: [Incorrect summation with Hermitian matrices · Issue #3242 · jump-dev/JuMP.jl · GitHub](https://github.com/jump-dev/JuMP.jl/issues/3242)

We’ve only recently added support for `HermitianPSDCone` and the associated `Complex` support, but this is a pretty major nasty on our part. It took me a while to find!

cc @blegat

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [February 27, 2023, 9:02am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/7 "2023-02-27T09:02:39Z")

</div>

Wow, you tracked down and fixed the bug on a Sunday. That’s some amazing dedication, thanks!

May I suggest to add this code as an example in the documentation for complex numbers? There are no examples there, and this is a simple and well-known problem.

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [February 27, 2023, 9:45am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/8 "2023-02-27T09:45:00Z")

</div>

> [@araujoms](#):
>
> this is a simple and well-known problem.

Is there an accessible reference one could link to for this?

---

<div class="post-metadata">

**Author:** ![blegat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blegat/32/217090_2.png) [@blegat](https://discourse.julialang.org/u/blegat)\
**Post date:** [February 27, 2023, 9:51am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/9 "2023-02-27T09:51:46Z")

</div>

For @odow, it was already Monday in New-Zealand ^^  
@araujoms Can you check that your model now works with JuMP#master ?  
I agree it would make a nice tutorial, quantum information was one of the motivation for adding Complex number support. A reference would be helpful indeed.

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [February 27, 2023, 10:02am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/10 "2023-02-27T10:02:01Z")

</div>

There’s always [Wikipedia](https://en.wikipedia.org/wiki/Quantum_state_discrimination), but that article is not so nice. A better reference would be [this review](https://arxiv.org/abs/1707.02571) or Section 11.3 of Bergou’s book, that I tried to link but got blocked by the spam filter.

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [February 27, 2023, 10:16am UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/11 "2023-02-27T10:16:43Z")

</div>

Just tested with the git version, now the following code works:

```julia
function discriminate(d,n)
    model = Model(SCS.Optimizer)
    rho = [random_state(d) for i in 1:n]
	E = [@variable(model, [1:d, 1:d] in HermitianPSDCone()) for i in 1:n-1]
	lastE = Hermitian(I - sum(E[i] for i in 1:n-1))
	@constraint(model, lastE in HermitianPSDCone())
	obj = real(sum(dot(rho[i],E[i]) for i in 1:n-1)+dot(rho[n],lastE))/n
    @objective(model, Max, obj)
    optimize!(model)
    print(value(obj))
end	

```

---

<div class="post-metadata">

**Author:** ![blegat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blegat/32/217090_2.png) [@blegat](https://discourse.julialang.org/u/blegat)\
**Post date:** [February 27, 2023, 12:01pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/12 "2023-02-27T12:01:48Z")

</div>

Thanks for the quick reply, this should be fixed in JuMP v1.8.2

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [February 27, 2023, 10:50pm UTC](https://discourse.julialang.org/t/error-when-constraining-variable-to-be-hermitian-psd/95223/13 "2023-02-27T22:50:41Z")

</div>

@araujoms I’ve started a tutorial, but I’m not a domain expert so any comments/suggestions would be helpful:

> <https://github.com/jump-dev/JuMP.jl/pull/3250/files#r1119395512>
>
> x-ref https://github.com/jump-dev/JuMP.jl/issues/2348#issuecomment-1446206831
> 
> …
> Also fixes https://github.com/jump-dev/JuMP.jl/pull/3245#issuecomment-1447048453
> 
> Still a WIP, because I don't really know enough physics to write about the problem we're solving, or what the solution represents.
> 
> Preview: https://jump.dev/JuMP.jl/previews/PR3250/tutorials/conic/quantum\_discrimination/
