Skip to content

Commit e137892

Browse files
author
Axel Dahlberg
committed
Updated estimation of state and p_succ in FEU and finished implementation of WFQ
1 parent 674ec94 commit e137892

File tree

4 files changed

+189
-121
lines changed

4 files changed

+189
-121
lines changed

qlinklayer/feu.py

Lines changed: 66 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import abc
2-
from numpy import kron, zeros
2+
from numpy import kron, sqrt
33
from netsquid.qubits import dm_fidelity
4-
from easysquid.toolbox import EasySquidException
54
from qlinklayer.toolbox import LinkLayerException
65
from netsquid.qubits.ketstates import s00, s01, s10, s11, b01, b11
76

@@ -45,7 +44,6 @@ def __init__(self, node, mhp_service):
4544
"""
4645
self.node = node
4746
self.mhp_service = mhp_service
48-
self.estimated_fidelity = self._estimate_fidelity()
4947
self.achievable_fidelities = self._calculate_achievable_fidelities()
5048

5149
def update_components(self, node=None, mhp_service=None):
@@ -82,11 +80,9 @@ def _calculate_achievable_fidelities(self):
8280
raise LinkLayerException("A and B have different bright state sets! Fidelity calculation unsupported")
8381

8482
achievable = []
85-
params = self._extract_params()
8683
for alphaA, alphaB in zip(bright_statesA, bright_statesB):
87-
params = (params[0], params[1], alphaA, alphaB, params[4], params[5])
8884
ideal_state = kron(b01.H, b01) # (|01> + |10>)(<01| + <10|)
89-
estimated_state = self._calculate_estimated_state(*params)
85+
estimated_state = self._calculate_estimated_state(alphaA, alphaB)
9086
fidelity = float(dm_fidelity(estimated_state, ideal_state, squared=True))
9187
achievable.append((alphaA, fidelity))
9288

@@ -126,16 +122,15 @@ def recalculate_estimate(self):
126122
self.estimated_fidelity = self._estimate_fidelity()
127123
return self.estimated_fidelity
128124

129-
def _estimate_fidelity(self):
125+
def _estimate_fidelity(self, alphaA=None, alphaB=None):
130126
"""
131127
Calculates the fidelity by extracting parameters from the mhp components, calculating an estimated state of
132128
the entangled qubit, and computing the fidelity with the ideal state.
133129
:return: float
134130
Estimated fidelity based on the component parameters
135131
"""
136-
params = self._extract_params()
137132
ideal_state = kron(b01.H, b01) # (|01> + |10>)(<01| + <10|)
138-
estimated_state = self._calculate_estimated_state(*params)
133+
estimated_state = self._calculate_estimated_state(alphaA, alphaB)
139134
return float(dm_fidelity(estimated_state, ideal_state, squared=True))
140135

141136
def _compute_total_detection_probabilities(self):
@@ -167,29 +162,51 @@ def _compute_total_detection_probability_of_node(self, node):
167162

168163
return total_detection_eff
169164

170-
def _compute_conditional_detection_probabilities(self, alpha):
165+
def _compute_conditional_detection_probabilities(self, alphaA=None, alphaB=None):
171166
"""
172167
Computes the probabilites p_uu, p_ud, pdu, pdd as given in eq (10) in https://arxiv.org/src/1712.07567v2/anc/SupplementaryInformation.pdf
173168
Note that this assumed low detection efficiencies
174-
:return:
169+
If either alphaA or alphaB is None, then alpha is assumed to be the same for the two nodes.
170+
171+
:return: tuple of floats
172+
(p_uu, p_ud, pdu, pdd)
175173
"""
174+
if alphaA is None and alphaB is None:
175+
raise LinkLayerException("alphaA or alphaB needs to be specified")
176+
if alphaA is None:
177+
alphaA = alphaB
178+
if alphaB is None:
179+
alphaB = alphaA
176180

177181
p_det_A, p_det_B = self._compute_total_detection_probabilities()
178182
p_dc = self.mhp_service.conn.midpoint.pdark
183+
# Dark count probabilities for both detectors
184+
p_no_dc = (1 - p_dc)**2
185+
p_at_least_one_dc = 1 - p_no_dc
186+
187+
prob_click_given_two_photons = (p_no_dc * (p_det_A*(1-p_det_B) + p_det_B*(1-p_det_A) + p_det_A*p_det_B) +
188+
p_at_least_one_dc * (1-p_det_A) * (1-p_det_B))
189+
p_uu = alphaA * alphaB * prob_click_given_two_photons
179190

180-
# TODO I don't think this is correct
181-
prob_click_given_two_photons = ((1 - p_dc)**2 * (p_det_A*(1-p_det_B) + p_det_B*(1-p_det_A) + p_det_A*p_det_B) +
182-
2 * p_dc * (1-p_dc) * (1-p_det_A) * (1-p_det_B))
183-
p_uu = alpha**2 * prob_click_given_two_photons
191+
prob_click_given_photon_A = p_no_dc * p_det_A + p_at_least_one_dc * (1-p_det_A)
192+
prob_click_given_photon_B = p_no_dc * p_det_B + p_at_least_one_dc * (1-p_det_B)
193+
p_ud = alphaA * (1-alphaB) * prob_click_given_photon_A
194+
p_du = alphaB * (1-alphaA) * prob_click_given_photon_B
184195

185-
prob_click_given_photon_A = (1-p_dc)**2*p_det_A + 2*p_dc*(1-p_dc)*(1-p_det_A)
186-
prob_click_given_photon_B = (1-p_dc)**2*p_det_B + 2*p_dc*(1-p_dc)*(1-p_det_B)
187-
p_ud = alpha * (1-alpha) * prob_click_given_photon_A
188-
p_du = alpha * (1-alpha) * prob_click_given_photon_B
196+
prob_click_given_no_photons = p_at_least_one_dc
197+
p_dd = (1 - alphaA) * (1 - alphaB) * prob_click_given_no_photons
189198

190-
prob_click_given_no_photons =
199+
return p_uu, p_ud, p_du, p_dd
191200

192-
# TODO NOT FINISHED!!!
201+
def _estimate_success_probability(self, alphaA=None, alphaB=None):
202+
"""
203+
Computes the success probability as the sum of p_uu, p_ud, p_du, p_dd as defined in eq (10) in
204+
https://arxiv.org/src/1712.07567v2/anc/SupplementaryInformation.pdf
205+
If either alphaA or alphaB is None, then alpha is assumed to be the same for the two nodes.
206+
:return: float
207+
The success probability
208+
"""
209+
return sum(self._compute_conditional_detection_probabilities(alphaA, alphaB))
193210

194211
def _extract_params(self):
195212
"""
@@ -212,85 +229,29 @@ def _extract_params(self):
212229

213230
return etaA, etaB, alphaA, alphaB, pdark, dp_photon
214231

215-
@staticmethod
216-
def _calculate_estimated_state(etaA, etaB, alphaA, alphaB, pdark, dp_photon):
217-
"""
218-
Calculates an estimated state based on the provided parameters. Adapted from "Near-term repeater experiments
219-
with NV centers: overcoming the limitations of direct transmission"
220-
:param etaA: float
221-
Transmitivity of fibre from A to midpoint
222-
:param etaB: float
223-
Transmitivity of fibre from B to midpoint
224-
:param alphaA: float
225-
Bright state population of generated state at node A
226-
:param alphaB: float
227-
Bright state population of generated state at node B
228-
:param pdark: float
229-
Probability of a dark count occurrence at the midpoint
230-
:param dp_photon: float
231-
Dephasing parameter of photon
232+
def _calculate_estimated_state(self, alphaA=None, alphaB=None):
233+
"""
234+
Calculates an estimated state based on the provided parameters. See eq (8) in
235+
https://arxiv.org/src/1712.07567v2/anc/SupplementaryInformation.pdf
236+
232237
:return: obj `~numpy.matrix`
233238
A density matrix of the estimated entangled state
234239
"""
235-
if pdark == 1:
236-
raise EasySquidException("Probability of dark count 1 does not allow for generating entanglement!")
237-
238-
# Calculate the probability that the left or right detector click depending on the probability of emission
239-
# Probability of click for photon from A
240-
p0 = alphaA * (1 - alphaB) * etaA
241-
242-
# Probability of click for photon from B
243-
p0 += (1 - alphaA) * alphaB * etaB
244-
245-
# Probility of click for photons from both
246-
p0 += alphaA * alphaB * (1 - (1 - etaA) * (1 - etaB))
247-
p0 *= 0.5
248-
249-
# Due to symmetries the probability is the same for the other detector
250-
p1 = p0
240+
if self._estimate_success_probability(alphaA, alphaB) == 0:
241+
raise LinkLayerException("Cannot estimate state when success probability is zero")
242+
p_uu, p_ud, p_du, p_dd = self._compute_conditional_detection_probabilities(alphaA, alphaB)
251243

252-
# Calculate the probability that neither detector clicks
253-
p2 = (1 - etaA * alphaA) * (1 - etaB * alphaB)
244+
visibility = self.mhp_service.conn.midpoint.visibility
254245

255-
if p2 == 1:
256-
raise EasySquidException("Probability of photons reaching detectors is zero!")
246+
ent_state = (p_ud * dm10 + # |10><10| part
247+
p_du * dm01 + # |01><01| part
248+
sqrt(visibility * p_ud * p_du) * kron(s10.H, s01) + # |10><01| part
249+
sqrt(visibility * p_ud * p_du) * kron(s01.H, s10)) # |01><10| part
257250

258-
# Calculate the probability of dark counts occuring within the detection window
259-
# Time window in nanoseconds, dark rate in Hz
251+
unnormalised_state = ent_state + p_uu * dm11 + p_dd * dm00
260252

261-
# Calculate the probability of entanglement (only one photon causes the detector to click)
262-
pent = alphaA * (1 - alphaB) * etaA +\
263-
(1 - alphaA) * alphaB * etaB
264-
265-
# Calculate the post-measurement state in the case that a detector clicks due to a photon from A or B
266-
a = dp_photon
267-
b = 1 - dp_photon
268-
rho0 = (pent / (p0 + p1)) * (a * dm_psi_plus + b * dm_psi_minus) + (1 - pent / (p0 + p1)) * dm11
269-
270-
# Calculate the post-measurement state in the case that a dark count causes the detector to click
271-
if p2 != 0:
272-
# Probability that neither endpoint emits a photon
273-
rho2 = (1 - alphaA) * (1 - alphaB) * dm00
274-
275-
# Probability that left endpoint emits a photon and it gets lost
276-
rho2 += (alphaA * (1 - alphaB) * (1 - etaA)) * dm10
277-
278-
# Probability that right endpoint emits a photon and it gets lost
279-
rho2 += ((1 - alphaA) * alphaB * (1 - etaB)) * dm01
280-
281-
# Probability that both endpoints emit a photon and both are lost
282-
rho2 += (1 - etaA) * (1 - etaB) * alphaA * alphaB * dm11
283-
rho2 *= (1 / p2)
284-
285-
# Probability of no clicks is zero then there is no influence
286-
else:
287-
rho2 = zeros((4, 4))
288-
289-
# Calculate the probability of registering a click in only one detector
290-
Y = (p0 + p1) * (1 - pdark) + 2 * p2 * pdark * (1 - pdark)
291-
292-
# Calculate the effective accepted state if a click in one detector occurs
293-
estimated_rho = (1 / Y) * ((p0 + p1) * (1 - pdark) * rho0 + 2 * p2 * pdark * (1 - pdark) * rho2)
253+
# Normalise the state
254+
estimated_rho = unnormalised_state / (p_uu + p_ud + p_du + p_dd)
294255

295256
return estimated_rho
296257

@@ -324,17 +285,19 @@ def optimize_bright_state_population(self, p_success, min_fidelity):
324285

325286
return bright_state_populations
326287

327-
def estimate_time_to_process(self, scheduler_request, units="seconds"):
288+
def estimate_nr_of_attempts(self, scheduler_request):
328289
"""
329-
Computes the estimated time to process a request (assuming that this is the only request in the queues
330-
and that its ready)
290+
Computes the estimated number of entanglement generation attempts needed generate ONE pair in the given request
291+
(assuming that this is the only request in the queues and that its ready)
331292
332-
The 'units' argument can be used to choose whether what is returned is in seconds or nr of mhp cycles
333293
:param scheduler_request: :obj:`~qlinklayer.scheduler.SchedulerRequest`
334-
:param units: str (either "seconds" or "mhp_cycles")
335-
:return: float or int
294+
:return: float
336295
"""
337-
if not units in ["seconds", "mhp_cycles"]:
338-
raise ValueError("'units' need to be 'seconds' or 'mhp_cycles'")
339-
# TODO implement this
340-
return 1
296+
alpha = self.select_bright_state(scheduler_request.min_fidelity)
297+
# Get success probability given alpha
298+
p_succ = self._estimate_success_probability(alpha)
299+
300+
# Estimate number of attempts needed
301+
est_nr_attempts = 1 / p_succ
302+
303+
return est_nr_attempts

qlinklayer/localQueue.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,23 @@ def update_mhp_cycle_number(self, current_cycle, max_cycle):
429429
logger.debug("Item is ready to be scheduled")
430430

431431

432+
class _WFQLocalQueueItem(_EGPLocalQueueItem):
433+
def __init__(self, request, seq, qid, timeout_callback):
434+
super().__init__(request, seq, qid, timeout_callback)
435+
436+
# Store virt finish and est nr of MHP cycles per pair (used to update the virt finish)
437+
self.virtual_finish = request.init_virtual_finish
438+
self.cycles_per_pair = request.est_cycles_per_pair
439+
440+
def update_virtual_finish(self):
441+
"""
442+
Adds est_cycles_per_pair to virtual_finish
443+
:return: None
444+
"""
445+
if not self.request.atomic:
446+
self.virtual_finish += self.cycles_per_pair
447+
448+
432449
class _TimeoutLocalQueueItem(_LocalQueueItem, Entity):
433450
def __init__(self, request, seq, lifetime=0.0):
434451
"""

0 commit comments

Comments
 (0)