-
Notifications
You must be signed in to change notification settings - Fork 0
/
optimize_measurements.jl
267 lines (223 loc) · 8.65 KB
/
optimize_measurements.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
export optimize_measurement
"""
[`LocalSignaling`](@ref) scenario:
optimize_measurement(
scenario :: LocalSignaling,
game :: BellGame,
ρ_states :: Vector{<:AbstractMatrix}
)
Finds the measurement that optimizes the score of the [`BellGame`](@ref) against
the set of quantum states `ρ_states`.
The optimization is performed with the following semi-definite program:
```math
\\begin{aligned}
&\\max_{\\{\\Pi_y\\}} \\sum_{x,y} G_{x,y} \\text{Tr}[\\Pi_y \\rho_x] \\\\
&s.t. \\quad \\sum_y \\Pi_y = \\mathbb{I}, \\quad \\Pi_y \\geq 0
\\end{aligned}
```
"""
function optimize_measurement(
scenario::LocalSignaling,
game::BellGame,
ρ_states::Vector{<:AbstractMatrix};
atol=1e-7::Float64
) :: Dict
if scenario.X != length(ρ_states)
throw(DomainError(scenario, "expected length of `ρ_states` is $(scenario.X)), but got $(length(ρ_states)) instead"))
elseif size(ρ_states[1]) != (scenario.d,scenario.d)
throw(DomainError(ρ_states, "dimension of `ρ_states` is not $(scenario.d)"))
end
states = map(ρ -> ρ isa State ? ρ : State(ρ, atol=atol), ρ_states)
norm_game_vector = convert(Vector{Int64}, game)
norm_bound = norm_game_vector[end]
norm_game = reshape(norm_game_vector[1:(end-1)], (scenario.Y-1, scenario.X))
# add povm variables and constraints
Π_vars = map(i -> HermitianSemidefinite(scenario.d), 1:scenario.Y)
constraints = (sum(map(Π_y -> real(Π_y), Π_vars)) == Matrix{Float64}(I, scenario.d, scenario.d))
constraints += (sum(map(Π_y -> imag(Π_y), Π_vars)) == zeros(Float64, scenario.d, scenario.d))
# sum up the state contibutions for each row
H_y = map(row_id -> sum(norm_game[row_id,:] .* states), 1:scenario.Y-1)
# add the objective
objective = maximize(real(tr(sum(Π_vars[1:end-1] .* H_y))), constraints)
solve!(objective, SCS.Optimizer())
# parse/return results
score = objective.optval
violation = score - norm_bound
Π_opt = _opt_vars_to_povm(map(Π_y -> Π_y.value, Π_vars))
Dict(
"violation" => violation,
"povm" => Π_opt,
"game" => game,
"scenario" => scenario,
"states" => states
)
end
"""
[`BipartiteNonSignaling`](@ref) scenario:
optimize_measurement(
game :: BellGame,
scenario :: BipartiteNonSignaling,
ρ_AB :: AbstractMatrix;
A_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}},
) :: Dict
Find Bob's measurement which optimizes a `BellGame`'s score for the shared quantum
state `ρ_AB` and POVM measurement applied by Alice.
The following semi-definite program optimizes the Bob's POVM:
```math
\\begin{aligned}
&\\max_{\\{\\Pi_b^y\\}} \\sum_{a,b,x,y} G_{a,b,x,y}\\text{Tr}[(\\Pi_a^x \\otimes \\Pi_b^y)\\rho_{AB}] \\\\
&s.t. \\quad \\sum_b \\Pi_b^y = \\mathbb{I},\\quad \\Pi_b^y \\geq 0 \\quad \\forall\\; y
\\end{aligned}
```
optimize_measurement(
game :: BellGame,
scenario :: BipartiteNonSignaling,
ρ_AB :: AbstractMatrix;
B_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}},
) :: Dict
Find Alice's measurement which optimizes a `BellGame`'s score for the shared quantum
state `ρ_{AB}` and POVM measurement applied by Bob.
The following semi-definite program optimizes the Alice's POVM:
```math
\\begin{aligned}
&\\max_{\\{\\Pi_a^x\\}} \\sum_{a,b,x,y} G_{a,b,x,y}\\text{Tr}[(\\Pi_a^x \\otimes \\Pi_b^y)\\rho_{AB}] \\\\
&s.t. \\quad \\sum_a \\Pi_a^x = \\mathbb{I},\\quad \\Pi_a^x \\geq 0 \\quad \\forall \\;x
\\end{aligned}
```
"""
function optimize_measurement(
scenario::BipartiteNonSignaling,
game::BellGame,
ρ_AB :: AbstractMatrix;
A_POVMs=Vector{POVM}(undef,0) :: Vector{<:AbstractVector{<:AbstractMatrix}},
B_POVMs=Vector{POVM}(undef,0) :: Vector{<:AbstractVector{<:AbstractMatrix}},
atol=1e-7::Float64
) :: Dict
ρ = ρ_AB isa State ? ρ_AB : State(ρ_AB, atol=atol)
if length(A_POVMs) > 0
return _optimize_measurement_B(scenario, game, ρ, A_POVMs, atol=atol)
elseif length(B_POVMs) > 0
return _optimize_measurement_A(scenario, game, ρ, B_POVMs, atol=atol)
else
throw(DomainError((A_POVMs,B_POVMs), "either `A_POVMs` or `B_POVMs` must be specified."))
end
end
# """
# Helper function for optimizing Bob's POVM
# """
function _optimize_measurement_B(
scenario::BipartiteNonSignaling,
game::BellGame,
ρ_AB :: AbstractMatrix,
A_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}};
atol=1e-7::Float64
) :: Dict
if !(scenario.X == length(A_POVMs))
throw( DomainError(
(scenario.X, " != length(A_POVMs)"),
"A distinct POVM is not specified for input `X` of `BipartiteNonSignaling` scenario"
))
elseif !(all(i -> scenario.A == length(A_POVMs[i]), 1:scenario.X ))
throw( DomainError(
A_POVMs, "Each POVM must have $(scenario.A) outputs."
))
end
Π_Ax = map(Π -> Π isa POVM ? Π : POVM(Π, atol=atol), A_POVMs)
ρ_dim = size(ρ_AB,1)
Π_A_dim = size(A_POVMs[1][1],1)
# The dimension of Bob's outputs
Π_B_dim = (ρ_dim % Π_A_dim == 0) ? Int64(ρ_dim / Π_A_dim) : throw(DomainError(
ρ_dim, "`size(ρ_Ab)` must equal `size(Π_A)*size(ΠB)`."
))
# Bob's POVM variables to optimize
B_POVMs = map(y -> map(b -> HermitianSemidefinite(Π_B_dim), 1:scenario.B), 1:scenario.Y)
# Objective function
problem = maximize(real(
sum(x -> sum(y -> sum(a -> sum(b ->
game[(a-1)*scenario.B+b,(x-1)*scenario.Y+y]*tr(kron(Π_Ax[x][a],B_POVMs[y][b])*ρ_AB.M),
1:scenario.B), 1:scenario.A), 1:scenario.Y), 1:scenario.X)
))
# Completeness constraints for Bob's POVM
for y in 1:scenario.Y
problem.constraints += sum(real.(B_POVMs[y])) == Matrix{Float64}(I, Π_B_dim, Π_B_dim)
problem.constraints += sum(imag.(B_POVMs[y])) == zeros(Float64, Π_B_dim, Π_B_dim)
end
# optimize model
solve!(problem, SCS.Optimizer())
# parse/return results
score = problem.optval
violation = score - game.β
Π_B_opt = map(y -> _opt_vars_to_povm(map(Π_b -> Π_b.value, B_POVMs[y])), 1:scenario.Y)
Dict(
"violation" => violation,
"score" => score,
"game" => game,
"scenario" => scenario,
"state" => ρ_AB,
"A_POVMs" => Π_Ax,
"B_POVMs" => Π_B_opt
)
end
# """
# Helper function for optimizing Alice's POVM
# """
function _optimize_measurement_A(
scenario::BipartiteNonSignaling,
game::BellGame,
ρ_AB :: AbstractMatrix,
B_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}};
atol=1e-7::Float64
) :: Dict
if !(scenario.Y == length(B_POVMs))
throw( DomainError(
(scenario.Y, " != length(B_POVMs)"),
"A distinct POVM is not specified for input `Y` of `BipartiteNonSignaling` scenario"
))
elseif !(all(i -> scenario.B == length(B_POVMs[i]), 1:scenario.Y ))
throw( DomainError(
B_POVMs, "Each POVM must have $(scenario.B) outputs."
))
end
Π_By = map(Π -> Π isa POVM ? Π : POVM(Π, atol=atol), B_POVMs)
ρ_dim = size(ρ_AB,1)
Π_B_dim = size(B_POVMs[1][1],1)
# dimension of Alice's POVM
Π_A_dim = (ρ_dim % Π_B_dim == 0) ? Int64(ρ_dim / Π_B_dim) : throw(DomainError(
ρ_dim, "`size(ρ_Ab)` must equal `size(Π_A)*size(ΠB)`."
))
# Alice's POVM variables to optimize
A_POVMs = map(x -> map(a -> HermitianSemidefinite(Π_A_dim), 1:scenario.A), 1:scenario.X)
# objective function
problem = maximize(real(
sum(x -> sum(y -> sum(a -> sum(b ->
game[(a-1)*scenario.B+b,(x-1)*scenario.Y+y]*tr(kron(A_POVMs[x][a],Π_By[y][b])*ρ_AB.M),
1:scenario.B), 1:scenario.A), 1:scenario.Y), 1:scenario.X)
))
# adding completeness constraints
for x in 1:scenario.X
problem.constraints += sum(real.(A_POVMs[x])) == Matrix{Float64}(I, Π_A_dim, Π_A_dim)
problem.constraints += sum(imag.(A_POVMs[x])) == zeros(Float64, Π_A_dim, Π_A_dim)
end
# optimize model
solve!(problem, SCS.Optimizer())
# parse/return results
score = problem.optval
violation = score - game.β
Π_A_opt = map( x -> _opt_vars_to_povm(map(Π_a -> Π_a.value, A_POVMs[x])), 1:scenario.X)
Dict(
"violation" => violation,
"score" => score,
"game" => game,
"scenario" => scenario,
"state" => ρ_AB,
"A_POVMs" => Π_A_opt,
"B_POVMs" => Π_By
)
end
# """
# Helper function for converting POVM optimization variables to a POVM
# """
function _opt_vars_to_povm(povm::Vector{<:AbstractMatrix}; atol=1) :: POVM
Π = is_povm(povm,atol=atol) ? POVM(povm,atol=atol) : throw(DomainError(povm, "not a povm"))
Π
end