sequence 0.8.5.dev81472917__tar.gz → 0.8.5.dev217420613__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/PKG-INFO +1 -1
  2. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/pyproject.toml +1 -1
  3. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/bsm.py +1 -1
  4. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/memory.py +2 -2
  5. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/generation/single_heralded.py +30 -28
  6. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/quantum_manager.py +6 -8
  7. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/quantum_utils.py +33 -26
  8. sequence-0.8.5.dev217420613/sequence/network_management/__init__.py +4 -0
  9. sequence-0.8.5.dev217420613/sequence/network_management/forwarding.py +102 -0
  10. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/network_management/network_manager.py +53 -12
  11. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/network_management/reservation.py +4 -4
  12. sequence-0.8.5.dev217420613/sequence/network_management/routing_distributed.py +731 -0
  13. sequence-0.8.5.dev217420613/sequence/network_management/routing_static.py +78 -0
  14. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/dqc_net_topo.py +2 -2
  15. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/node.py +35 -3
  16. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/router_net_topo.py +49 -22
  17. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/topology.py +5 -5
  18. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/utils/config_generator.py +1 -1
  19. sequence-0.8.5.dev81472917/sequence/network_management/__init__.py +0 -4
  20. sequence-0.8.5.dev81472917/sequence/network_management/routing.py +0 -117
  21. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/README.md +0 -0
  22. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/__init__.py +0 -0
  23. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/app/__init__.py +0 -0
  24. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/app/random_request.py +0 -0
  25. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/app/request_app.py +0 -0
  26. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/app/teleport_app.py +0 -0
  27. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/__init__.py +0 -0
  28. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/beam_splitter.py +0 -0
  29. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/circuit.py +0 -0
  30. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/detector.py +0 -0
  31. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/fiber_stretcher.py +0 -0
  32. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/interferometer.py +0 -0
  33. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/light_source.py +0 -0
  34. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/mirror.py +0 -0
  35. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/optical_channel.py +0 -0
  36. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/photon.py +0 -0
  37. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/spdc_lens.py +0 -0
  38. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/switch.py +0 -0
  39. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/transducer.py +0 -0
  40. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/components/transmon.py +0 -0
  41. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/constants.py +0 -0
  42. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/__init__.py +0 -0
  43. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/entanglement_protocol.py +0 -0
  44. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/generation/__init__.py +0 -0
  45. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/generation/barret_kok.py +0 -0
  46. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/generation/generation_base.py +0 -0
  47. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/generation/generation_message.py +0 -0
  48. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/purification/__init__.py +0 -0
  49. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/purification/bbpssw_bds.py +0 -0
  50. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/purification/bbpssw_circuit.py +0 -0
  51. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/purification/bbpssw_protocol.py +0 -0
  52. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/swapping.py +0 -0
  53. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/entanglement_management/teleportation.py +0 -0
  54. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/__init__.py +0 -0
  55. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/app.py +0 -0
  56. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/argonne.png +0 -0
  57. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/attributions_req +0 -0
  58. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/bsmnode.png +0 -0
  59. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/detector.png +0 -0
  60. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/logo.png +0 -0
  61. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/photonsource.png +0 -0
  62. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/quantum.png +0 -0
  63. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/repeater.png +0 -0
  64. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/router.png +0 -0
  65. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/sequence.jpg +0 -0
  66. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/bsmnode.svg +0 -0
  67. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/detector.svg +0 -0
  68. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/photonsource.svg +0 -0
  69. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/quantum.svg +0 -0
  70. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/repeater.svg +0 -0
  71. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/router.svg +0 -0
  72. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/svg/temp.svg +0 -0
  73. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/assets/temp.png +0 -0
  74. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/css_styles.py +0 -0
  75. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/default_params.json +0 -0
  76. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/default_templates.json +0 -0
  77. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/graph_comp.py +0 -0
  78. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/layout.py +0 -0
  79. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/menus.py +0 -0
  80. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/run_gui.py +0 -0
  81. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/simulator_bindings.py +0 -0
  82. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/starlight.json +0 -0
  83. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/test.txt +0 -0
  84. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/gui/user_templates.json +0 -0
  85. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/__init__.py +0 -0
  86. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/entity.py +0 -0
  87. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/event.py +0 -0
  88. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/eventlist.py +0 -0
  89. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/process.py +0 -0
  90. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/quantum_state.py +0 -0
  91. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/kernel/timeline.py +0 -0
  92. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/message.py +0 -0
  93. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/protocol.py +0 -0
  94. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/qkd/BB84.py +0 -0
  95. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/qkd/__init__.py +0 -0
  96. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/qkd/cascade.py +0 -0
  97. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/qlan/correction.py +0 -0
  98. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/qlan/graph_gen.py +0 -0
  99. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/qlan/measurement.py +0 -0
  100. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/resource_management/__init__.py +0 -0
  101. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/resource_management/memory_manager.py +0 -0
  102. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/resource_management/resource_manager.py +0 -0
  103. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/resource_management/rule_manager.py +0 -0
  104. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/__init__.py +0 -0
  105. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/qkd_topo.py +0 -0
  106. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/qlan/client.py +0 -0
  107. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/qlan/orchestrator.py +0 -0
  108. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/topology/qlan_star_topo.py +0 -0
  109. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/utils/__init__.py +0 -0
  110. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/utils/encoding.py +0 -0
  111. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/utils/log.py +0 -0
  112. {sequence-0.8.5.dev81472917 → sequence-0.8.5.dev217420613}/sequence/utils/noise.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sequence
3
- Version: 0.8.5.dev81472917
3
+ Version: 0.8.5.dev217420613
4
4
  Summary: Simulator of QUantum Network Communication (SeQUeNCe) is an open-source tool that allows modeling of quantum networks including photonic network components, control protocols, and applications.
5
5
  Keywords: quantum,network,discrete,event,simulator
6
6
  Author: Xiaoliang Wu, Joaquin Chung, Alexander Kolar, Alexander Kiefer, Eugene Wang, Tian Zhong, Rajkumar Kettimuthu, Martin Suchara, Robert Hayek, Ansh Singal, Caitao Zhan
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sequence"
3
- version = "0.8.5.dev81472917"
3
+ version = "0.8.5.dev217420613"
4
4
  authors = [
5
5
  { name = "Xiaoliang Wu, Joaquin Chung, Alexander Kolar, Alexander Kiefer, Eugene Wang, Tian Zhong, Rajkumar Kettimuthu, Martin Suchara, Robert Hayek, Ansh Singal, Caitao Zhan", email = "czhan@anl.gov" }
6
6
  ]
@@ -678,8 +678,8 @@ class SingleHeraldedBSM(BSM):
678
678
  log.logger.debug(f'{self.name}: photonic BSM failed')
679
679
  else:
680
680
  p0, p1 = self.photons
681
- # if both memory successfully emit the photon in this round (consider memory emission inefficiency)
682
681
  if self.get_generator().random() > p0.loss and self.get_generator().random() > p1.loss:
682
+ # if both photons successfully arrive (not lost in memory or optical fiber) and the BSM is successful
683
683
  for idx, photon in enumerate(self.photons):
684
684
  detector = self.detectors[idx]
685
685
  detector.get(photon)
@@ -128,7 +128,7 @@ class MemoryArray(Entity):
128
128
 
129
129
  Args:
130
130
  name (str): name of memory
131
- Return:
131
+ Returns:
132
132
  (Memory): the memory object
133
133
  """
134
134
  index = self.memory_name_to_index.get(name, -1)
@@ -463,7 +463,7 @@ class Memory(Entity):
463
463
  def get_bds_fidelity(self) -> float:
464
464
  """Will get the fidelity from the BDS state
465
465
 
466
- Return:
466
+ Returns:
467
467
  (float): the fidelity of the BDS state
468
468
  """
469
469
  state_obj = self.timeline.quantum_manager.get(self.qstate_key)
@@ -22,13 +22,29 @@ if TYPE_CHECKING:
22
22
 
23
23
  @EntanglementGenerationA.register(SINGLE_HERALDED)
24
24
  class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
25
+ """
26
+ Class for single heralded entanglement generation protocol A.
27
+ This protocol is used on the two end nodes of the entanglement generation process.
28
+
29
+ Attributes:
30
+ owner (Node): node that protocol instance is attached to.
31
+ name (str): label for protocol instance.
32
+ middle (str): name of the middle BSM node.
33
+ other (str): name of the other end node.
34
+ memory (Memory): memory object used for entanglement generation.
35
+ raw_fidelity (float): the raw fidelity of generated entangled pair.
36
+ raw_epr_errors (list[float]): the raw EPR pair Pauli error rates in X, Y, Z order.
37
+ bsm_res (list[int]): the BSM measurement results from the middle BSM node.
38
+ """
25
39
  def __init__(self, owner: Node, name: str, middle: str, other: str, memory: Memory,
26
40
  raw_fidelity: float = None, raw_epr_errors: list[float] = None):
27
41
  super().__init__(owner, name, middle, other, memory)
28
42
 
29
43
  self.protocol_type = SINGLE_HERALDED
30
- assert QuantumManager.get_active_formalism() == BELL_DIAGONAL_STATE_FORMALISM, \
31
- f"Single Heralded Entanglement generation protocol only supports Bell diagonal state formalism; got {QuantumManager.get_active_formalism()}"
44
+ active_formalism = QuantumManager.get_active_formalism()
45
+ assert_message = ("Single Heralded Entanglement generation protocol only"
46
+ f"supports Bell diagonal state formalism; got {active_formalism}")
47
+ assert active_formalism == BELL_DIAGONAL_STATE_FORMALISM, assert_message
32
48
 
33
49
  if raw_fidelity:
34
50
  self.raw_fidelity = raw_fidelity
@@ -40,8 +56,7 @@ class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
40
56
  if self.raw_epr_errors is None:
41
57
  self.raw_epr_errors = [1 / 3, 1 / 3, 1 / 3]
42
58
  if self.raw_epr_errors:
43
- assert len(self.raw_epr_errors) == 3, \
44
- "Raw EPR pair pauli error list should have three elements in X, Y, Z order."
59
+ assert len(self.raw_epr_errors) == 3, "Raw EPR pair pauli error list should have three elements in X, Y, Z order."
45
60
 
46
61
  self.bsm_res = [0, 0]
47
62
 
@@ -130,8 +145,7 @@ class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
130
145
 
131
146
  msg_type = msg.msg_type
132
147
 
133
- log.logger.debug("{} {} received message from node {} of type {}, round={}".format(
134
- self.owner.name, self.name, src, msg.msg_type, self.ent_round))
148
+ log.logger.debug(f"{self.owner.name} {self.name} received message from node {src} of type {msg.msg_type}, round={self.ent_round}")
135
149
 
136
150
  if msg_type is GenerationMsgType.NEGOTIATE: # primary -> non-primary
137
151
  # configure params
@@ -141,8 +155,7 @@ class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
141
155
 
142
156
  # get time for first excite event
143
157
  memory_excite_time = self.memory.next_excite_time
144
- min_time = max(self.owner.timeline.now(),
145
- memory_excite_time) + other_qc_delay - self.qc_delay + cc_delay # cc_delay time for NEGOTIATE_ACK
158
+ min_time = max(self.owner.timeline.now(), memory_excite_time) + other_qc_delay - self.qc_delay + cc_delay # cc_delay time for NEGOTIATE_ACK
146
159
  emit_time = self.owner.schedule_qubit(self.middle, min_time) # used to send memory
147
160
  self.expected_time = emit_time + self.qc_delay # expected time for middle BSM node to receive the photon
148
161
 
@@ -154,17 +167,13 @@ class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
154
167
 
155
168
  # send negotiate_ack
156
169
  other_emit_time = emit_time + self.qc_delay - other_qc_delay
157
- message = EntanglementGenerationMessage(GenerationMsgType.NEGOTIATE_ACK,
158
- self.remote_protocol_name,
159
- protocol_type=self.protocol_type,
160
- emit_time=other_emit_time)
170
+ message = EntanglementGenerationMessage(GenerationMsgType.NEGOTIATE_ACK, self.remote_protocol_name,
171
+ self.protocol_type, emit_time=other_emit_time)
161
172
  self.owner.send_message(src, message)
162
173
 
163
- # schedule start if necessary (current is first round, need second round),
164
- # else schedule update_memory (currently second round)
174
+ # schedule start if necessary (current is first round, need second round), else schedule update_memory (currently second round)
165
175
  # TODO: base future start time on resolution
166
- future_start_time = self.expected_time + self.owner.cchannels[
167
- self.middle].delay + 10 # delay is for sending the BSM_RES to end nodes, 10 is a small gap
176
+ future_start_time = self.expected_time + self.owner.cchannels[self.middle].delay + 10 # delay is for sending the BSM_RES to end nodes, 10 is a small gap
168
177
  if self.ent_round == 1:
169
178
  process = Process(self, "start", []) # for the second round
170
179
  else:
@@ -183,8 +192,7 @@ class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
183
192
 
184
193
  # schedule emit
185
194
  emit_time = self.owner.schedule_qubit(self.middle, msg.emit_time)
186
- assert emit_time == msg.emit_time, \
187
- f"Invalid eg emit times {emit_time} {msg.emit_time} {self.owner.timeline.now()}"
195
+ assert emit_time == msg.emit_time, f"Invalid eg emit times {emit_time} {msg.emit_time} {self.owner.timeline.now()}"
188
196
 
189
197
  process = Process(self, "emit_event", [])
190
198
  event = Event(msg.emit_time, process)
@@ -210,7 +218,7 @@ class SingleHeraldedA(EntanglementGenerationA, QuantumCircuitMixin):
210
218
  resolution = msg.resolution
211
219
 
212
220
  log.logger.debug("{} received MEAS_RES={} at time={:,}, expected={:,}, resolution={}, round={}".format(
213
- self.owner.name, detector, time, self.expected_time, resolution, self.ent_round))
221
+ self.owner.name, detector, time, self.expected_time, resolution, self.ent_round))
214
222
 
215
223
  if valid_trigger_time(time, self.expected_time, resolution):
216
224
  self.bsm_res[detector] += 1
@@ -244,9 +252,7 @@ class SingleHeraldedB(EntanglementGenerationB):
244
252
  bsm (SingleAtomBSM or SingleHeraldedBSM): bsm object calling method.
245
253
  info (Dict[str, any]): information passed from bsm.
246
254
  """
247
- assert bsm.encoding == SINGLE_HERALDED, \
248
- "SingleHeraldedB should only be used with SingleHeraldedBSM."
249
-
255
+ assert bsm.encoding == SINGLE_HERALDED, "SingleHeraldedB should only be used with SingleHeraldedBSM."
250
256
  assert info['info_type'] == 'BSM_res'
251
257
 
252
258
  res = info['res']
@@ -254,10 +260,6 @@ class SingleHeraldedB(EntanglementGenerationB):
254
260
  resolution = bsm.resolution
255
261
 
256
262
  for node in self.others:
257
- message = EntanglementGenerationMessage(GenerationMsgType.MEAS_RES,
258
- receiver=None,
259
- protocol_type=self.protocol_type,
260
- detector=res,
261
- time=time,
262
- resolution=resolution)
263
+ message = EntanglementGenerationMessage(GenerationMsgType.MEAS_RES, None, self.protocol_type,
264
+ detector=res, time=time, resolution=resolution)
263
265
  self.owner.send_message(node, message)
@@ -551,8 +551,8 @@ class QuantumManagerDensity(QuantumManager):
551
551
  key = keys[0]
552
552
  num_states = len(all_keys)
553
553
  state_index = all_keys.index(key)
554
- state_0, state_1, prob_0 = \
555
- measure_entangled_state_with_cache_density(tuple(map(tuple, state)), state_index, num_states)
554
+ state_0, state_1, prob_0 = measure_entangled_state_with_cache_density(tuple(map(tuple, state)),
555
+ state_index, num_states)
556
556
  if meas_samp < prob_0:
557
557
  new_state = array(state_0, dtype=complex)
558
558
  result = 0
@@ -795,15 +795,13 @@ class QuantumManagerDensityFock(QuantumManager):
795
795
  key = keys[0]
796
796
  num_states = len(all_keys)
797
797
  state_index = all_keys.index(key)
798
- states, probs = \
799
- measure_entangled_state_with_cache_fock_density(state_tuple, state_index, num_states, povm_tuple,
800
- self.truncation)
798
+ states, probs = measure_entangled_state_with_cache_fock_density(state_tuple, state_index, num_states,
799
+ povm_tuple, self.truncation)
801
800
 
802
801
  else:
803
802
  indices = tuple([all_keys.index(key) for key in keys])
804
- states, probs = \
805
- measure_multiple_with_cache_fock_density(state_tuple, indices, len(all_keys), povm_tuple,
806
- self.truncation)
803
+ states, probs = measure_multiple_with_cache_fock_density(state_tuple, indices, len(all_keys),
804
+ povm_tuple, self.truncation)
807
805
 
808
806
  # calculate result based on measurement sample.
809
807
  prob_sum = cumsum(probs)
@@ -5,11 +5,12 @@ These should not be used directly, but accessed by a QuantumManager instance or
5
5
  """
6
6
 
7
7
  from functools import lru_cache
8
+ import warnings
8
9
  from math import sqrt
9
10
  import random
10
11
  import math
11
12
  from numpy import array, kron, identity, zeros, trace, outer, eye, clip
12
- from scipy.linalg import sqrtm
13
+ from scipy.linalg import LinAlgWarning, sqrtm
13
14
  from ..constants import EPSILON
14
15
 
15
16
 
@@ -34,8 +35,8 @@ def measure_state_with_cache(state: tuple[complex, complex], basis: tuple[tuple[
34
35
 
35
36
 
36
37
  @lru_cache(maxsize=1000)
37
- def measure_entangled_state_with_cache(state: tuple[complex], basis: tuple[tuple[complex]], state_index: int, num_states: int) \
38
- -> tuple[array, array, float]:
38
+ def measure_entangled_state_with_cache(state: tuple[complex], basis: tuple[tuple[complex]],
39
+ state_index: int, num_states: int) -> tuple[array, array, float]:
39
40
 
40
41
  state = array(state)
41
42
  u = array(basis[0], dtype=complex)
@@ -72,8 +73,8 @@ def measure_entangled_state_with_cache(state: tuple[complex], basis: tuple[tuple
72
73
 
73
74
 
74
75
  @lru_cache(maxsize=1000)
75
- def measure_multiple_with_cache(state: tuple[complex], basis: tuple[tuple[complex]], length_diff: int) \
76
- -> tuple[list[array], list[float]]:
76
+ def measure_multiple_with_cache(state: tuple[complex], basis: tuple[tuple[complex]],
77
+ length_diff: int) -> tuple[list[array], list[float]]:
77
78
 
78
79
  state = array(state)
79
80
  # construct measurement operators, projectors, and probabilities of measurement
@@ -109,8 +110,8 @@ def measure_state_with_cache_ket(state: tuple[complex, complex]) -> float:
109
110
 
110
111
 
111
112
  @lru_cache(maxsize=1000)
112
- def measure_entangled_state_with_cache_ket(state: tuple[complex], state_index: int, num_states: int) \
113
- -> tuple[array, array, float]:
113
+ def measure_entangled_state_with_cache_ket(state: tuple[complex], state_index: int,
114
+ num_states: int) -> tuple[array, array, float]:
114
115
 
115
116
  state = array(state)
116
117
  # generate measurement operators. measure qubit at state_index, with the measured qubit traced out
@@ -136,8 +137,8 @@ def measure_entangled_state_with_cache_ket(state: tuple[complex], state_index: i
136
137
 
137
138
 
138
139
  @lru_cache(maxsize=1000)
139
- def measure_multiple_with_cache_ket(state: tuple[complex], num_states: int, length_diff: int) \
140
- -> tuple[list[array], list[float]]:
140
+ def measure_multiple_with_cache_ket(state: tuple[complex], num_states: int,
141
+ length_diff: int) -> tuple[list[array], list[float]]:
141
142
 
142
143
  state = array(state)
143
144
  basis_count = 2 ** num_states
@@ -178,8 +179,8 @@ def measure_state_with_cache_density(state: tuple[tuple[complex, complex]]) -> f
178
179
 
179
180
 
180
181
  @lru_cache(maxsize=1000)
181
- def measure_entangled_state_with_cache_density(state: tuple[tuple[complex]], state_index: int, num_states: int) \
182
- -> tuple[array, array, float]:
182
+ def measure_entangled_state_with_cache_density(state: tuple[tuple[complex]], state_index: int,
183
+ num_states: int) -> tuple[array, array, float]:
183
184
 
184
185
  state = array(state)
185
186
 
@@ -211,8 +212,8 @@ def measure_entangled_state_with_cache_density(state: tuple[tuple[complex]], sta
211
212
 
212
213
 
213
214
  @lru_cache(maxsize=1000)
214
- def measure_multiple_with_cache_density(state: tuple[tuple[complex]], num_states: int, length_diff: int) \
215
- -> tuple[list[array], list[float]]:
215
+ def measure_multiple_with_cache_density(state: tuple[tuple[complex]],
216
+ num_states: int, length_diff: int) -> tuple[list[array], list[float]]:
216
217
 
217
218
  state = array(state)
218
219
  basis_count = 2 ** num_states
@@ -242,8 +243,8 @@ def measure_multiple_with_cache_density(state: tuple[tuple[complex]], num_states
242
243
 
243
244
 
244
245
  @lru_cache(maxsize=1000)
245
- def measure_state_with_cache_fock_density(state: tuple[tuple[complex]], povms: tuple[tuple[tuple[complex]]]) \
246
- -> tuple[list[array], list[float]]:
246
+ def measure_state_with_cache_fock_density(state: tuple[tuple[complex]],
247
+ povms: tuple[tuple[tuple[complex]]]) -> tuple[list[array], list[float]]:
247
248
  state = array(state)
248
249
  povms = [array(povm) for povm in povms]
249
250
 
@@ -256,7 +257,9 @@ def measure_state_with_cache_fock_density(state: tuple[tuple[complex]], povms: t
256
257
  if prob_list[i] <= 0:
257
258
  state_post_meas = None
258
259
  else:
259
- measure_op = sqrtm(povms[i])
260
+ with warnings.catch_warnings():
261
+ warnings.filterwarnings("ignore", category=LinAlgWarning)
262
+ measure_op = sqrtm(povms[i])
260
263
  state_post_meas = (measure_op @ state @ measure_op) / prob_list[i]
261
264
 
262
265
  state_list.append(state_post_meas)
@@ -265,9 +268,9 @@ def measure_state_with_cache_fock_density(state: tuple[tuple[complex]], povms: t
265
268
 
266
269
 
267
270
  @lru_cache(maxsize=1000)
268
- def measure_entangled_state_with_cache_fock_density(state: tuple[tuple[complex]], system_index: int, num_systems: int,
269
- povms: tuple[tuple[tuple[complex]]], truncation: int = 1) \
270
- -> tuple[list[array], list[float]]:
271
+ def measure_entangled_state_with_cache_fock_density(state: tuple[tuple[complex]], system_index: int,
272
+ num_systems: int, povms: tuple[tuple[tuple[complex]]],
273
+ truncation: int = 1) -> tuple[list[array], list[float]]:
271
274
 
272
275
  """Measure one subsystem of a larger composite system.
273
276
 
@@ -306,7 +309,9 @@ def measure_entangled_state_with_cache_fock_density(state: tuple[tuple[complex]]
306
309
  if prob_list[i] <= 0:
307
310
  state_post_meas = None
308
311
  else:
309
- measure_op = sqrtm(povm_list[i])
312
+ with warnings.catch_warnings():
313
+ warnings.filterwarnings("ignore", category=LinAlgWarning)
314
+ measure_op = sqrtm(povm_list[i])
310
315
  state_post_meas = (measure_op @ state @ measure_op) / prob_list[i]
311
316
 
312
317
  state_list.append(state_post_meas)
@@ -315,9 +320,9 @@ def measure_entangled_state_with_cache_fock_density(state: tuple[tuple[complex]]
315
320
 
316
321
 
317
322
  @lru_cache(maxsize=1000)
318
- def measure_multiple_with_cache_fock_density(state: tuple[tuple[complex]], indices: tuple[int], num_systems: int,
319
- povms: tuple[tuple[tuple[complex]]], truncation: int = 1) \
320
- -> tuple[list[array], list[float]]:
323
+ def measure_multiple_with_cache_fock_density(state: tuple[tuple[complex]], indices: tuple[int],
324
+ num_systems: int, povms: tuple[tuple[tuple[complex]]],
325
+ truncation: int = 1) -> tuple[list[array], list[float]]:
321
326
 
322
327
  """Measure multiple subsystems of a larger composite system.
323
328
 
@@ -372,7 +377,9 @@ def measure_multiple_with_cache_fock_density(state: tuple[tuple[complex]], indic
372
377
  if prob_list[i] <= 0:
373
378
  state_post_meas = None
374
379
  else:
375
- measure_op = sqrtm(povm_list[i])
380
+ with warnings.catch_warnings():
381
+ warnings.filterwarnings("ignore", category=LinAlgWarning)
382
+ measure_op = sqrtm(povm_list[i])
376
383
  state_post_meas = (measure_op @ state @ measure_op) / prob_list[i]
377
384
 
378
385
  state_list.append(state_post_meas)
@@ -382,8 +389,8 @@ def measure_multiple_with_cache_fock_density(state: tuple[tuple[complex]], indic
382
389
 
383
390
 
384
391
  @lru_cache(maxsize=1000)
385
- def density_partial_trace(state: tuple[tuple[complex]], indices: tuple[int], num_systems: int, truncation: int = 1) \
386
- -> array:
392
+ def density_partial_trace(state: tuple[tuple[complex]], indices: tuple[int],
393
+ num_systems: int, truncation: int = 1) -> array:
387
394
 
388
395
  """Traces out subsystems systems at given indices.
389
396
 
@@ -0,0 +1,4 @@
1
+ __all__ = ['routing_static', 'routing_distributed', 'forwarding', 'reservation', 'network_manager']
2
+
3
+ def __dir__():
4
+ return sorted(__all__)
@@ -0,0 +1,102 @@
1
+ """Forwarding protocol and forwarding message.
2
+
3
+ This module defines the `ForwardingProtocol` and `ForwardingMessage` classes.
4
+ """
5
+
6
+ from typing import TYPE_CHECKING
7
+ if TYPE_CHECKING:
8
+ from ..topology.node import Node
9
+
10
+ from enum import Enum
11
+ from ..protocol import StackProtocol
12
+ from ..message import Message
13
+ from ..utils import log
14
+
15
+
16
+ class ForwardingMessage(Message):
17
+ """Message used for communications between forwarding protocol instances.
18
+
19
+ Attributes:
20
+ msg_type (Enum): type of message, required by base `Message` class.
21
+ receiver (str): name of destination protocol instance.
22
+ payload (Message): message to be delivered to destination.
23
+ """
24
+
25
+ def __init__(self, msg_type: Enum, receiver: str, payload: Message):
26
+ super().__init__(msg_type, receiver)
27
+ self.payload = payload
28
+
29
+ def __str__(self):
30
+ return f"type={self.msg_type}, receiver={self.receiver}, payload={self.payload}"
31
+
32
+
33
+ class ForwardingProtocol(StackProtocol):
34
+ """Class to forward messages based on the forwarding table (from the `NetworkManager`) in the routing protocol.
35
+
36
+ Attributes:
37
+ owner (Node): node that protocol instance is attached to.
38
+ name (str): label for protocol instance.
39
+ """
40
+
41
+ def __init__(self, owner: "Node", name: str):
42
+ """Constructor for forwarding protocol.
43
+
44
+ Args:
45
+ owner (Node): node protocol is attached to.
46
+ name (str): name of protocol instance.
47
+ """
48
+ super().__init__(owner, name)
49
+
50
+ @property
51
+ def forwarding_table(self) -> dict[str, str]:
52
+ """Returns the forwarding table."""
53
+ return self.owner.network_manager.get_forwarding_table()
54
+
55
+ def received_message(self, src: str, msg: Message):
56
+ """Method to directly receive messages from node (should not be used)."""
57
+
58
+ raise Exception("Forwarding protocol should not call this function")
59
+
60
+ def init(self):
61
+ pass
62
+
63
+ def push(self, dst: str, msg: Message, next_hop: str = None):
64
+ """Method to receive message from upper protocols.
65
+
66
+ Routing packages the message and forwards it to the next node in the optimal path (determined by the forwarding table).
67
+
68
+ Args:
69
+ dst (str): name of destination node. If not None, resort to the forwarding table to get the next hop.
70
+ msg (Message): message to relay.
71
+ next_hop (str): name of next hop. If dst is None, next_hop shouldn't be None. next_hop directly tells the next hop.
72
+
73
+ Side Effects:
74
+ Will invoke `push` method of lower protocol or network manager.
75
+ """
76
+ assert dst != self.owner.name
77
+ forwarding_table = self.forwarding_table
78
+ new_msg = ForwardingMessage(Enum, self.name, msg)
79
+ if dst: # if dst is not None, use the forwarding table
80
+ next_hop = forwarding_table.get(dst, None)
81
+ if next_hop:
82
+ self._push(dst=next_hop, msg=new_msg)
83
+ else:
84
+ log.logger.error(f'No forwarding rule for dst {dst} at node {self.owner.name}')
85
+ elif next_hop: # if next_hop is not None, use next_hop
86
+ self._push(dst=next_hop, msg=new_msg)
87
+ else:
88
+ raise Exception('Both dst and next_hop are None!')
89
+
90
+ def pop(self, src: str, msg: ForwardingMessage):
91
+ """Message to receive reservation messages.
92
+
93
+ Messages are forwarded to the upper protocol.
94
+
95
+ Args:
96
+ src (str): node sending the message.
97
+ msg (ForwardingMessage): message received.
98
+
99
+ Side Effects:
100
+ Will call `pop` method of higher protocol.
101
+ """
102
+ self._pop(src=src, msg=msg.payload)
@@ -12,7 +12,10 @@ if TYPE_CHECKING:
12
12
  from ..protocol import StackProtocol
13
13
 
14
14
  from ..message import Message
15
- from .routing import StaticRoutingProtocol
15
+ from ..protocol import Protocol
16
+ from .routing_distributed import DistributedRoutingProtocol
17
+ from .routing_static import StaticRoutingProtocol
18
+ from .forwarding import ForwardingProtocol
16
19
  from .reservation import ResourceReservationProtocol, ResourceReservationMessage, RSVPMsgType
17
20
  from ..utils import log
18
21
 
@@ -44,6 +47,8 @@ class NetworkManager:
44
47
  name (str): name of the network manager instance.
45
48
  owner (QuantumRouter): node that protocol instance is attached to.
46
49
  protocol_stack (list[StackProtocol]): network manager protocol stack.
50
+ forwarding_table (dict[str, str]): mapping of destination node names to name of node for next hop.
51
+ routing_protocol (Protocol): routing protocol
47
52
  """
48
53
 
49
54
  def __init__(self, owner: "QuantumRouter", protocol_stack: "list[StackProtocol]"):
@@ -59,6 +64,8 @@ class NetworkManager:
59
64
  self.owner = owner
60
65
  self.protocol_stack = protocol_stack
61
66
  self.load_stack(protocol_stack)
67
+ self.forwarding_table = {}
68
+ self.routing_protocol = None
62
69
 
63
70
  def load_stack(self, stack: "list[StackProtocol]"):
64
71
  """Method to load a defined protocol stack.
@@ -143,17 +150,24 @@ class NetworkManager:
143
150
 
144
151
  self.protocol_stack[-1].push(responder, start_time, end_time, memory_size, target_fidelity, entanglement_number, identity)
145
152
 
146
- def update_forwarding_table(self, forwarding_table: dict) -> None:
147
- """Method to set the forwarding table in the routing_protocol in the network manager's protocol stack.
153
+ def set_forwarding_table(self, forwarding_table: dict) -> None:
154
+ """Method to set the forwarding table in the network manager
148
155
 
149
156
  Args:
150
157
  forwarding_table (dict): the forwarding table for this node, where the key is the destination node name
151
158
  and the value is the next hop
152
159
  """
153
- log.logger.info(f"{self.owner.name} update forwarding table: {forwarding_table}")
154
- static_routing_protocol = self.protocol_stack[0] # [0] is the static routing protocol
155
- for dst, next_hop in forwarding_table.items():
156
- static_routing_protocol.update_forwarding_rule(dst, next_hop)
160
+ log.logger.info(f"{self.owner.name} set forwarding table: {forwarding_table}")
161
+ self.forwarding_table = forwarding_table
162
+
163
+ def get_forwarding_table(self) -> dict[str, str]:
164
+ """Method to get the forwarding table in the network manager.
165
+
166
+ Returns:
167
+ dict[str, str]: the forwarding table for this node, where the key is the destination node name
168
+ and the value is the next hop
169
+ """
170
+ return self.forwarding_table
157
171
 
158
172
  def get_reservation_protocol(self) -> ResourceReservationProtocol:
159
173
  """Method to get the resource reservation protocol in the network manager's protocol stack.
@@ -166,8 +180,24 @@ class NetworkManager:
166
180
  return protocol
167
181
  raise ValueError("No resource reservation protocol found in the network manager's protocol stack")
168
182
 
183
+ def set_routing_protocol(self, routing_protocol: Protocol) -> None:
184
+ """Method to set the routing protocol in the network manager.
185
+
186
+ Args:
187
+ routing_protocol (Protocol): the routing protocol to set
188
+ """
189
+ self.routing_protocol = routing_protocol
190
+
191
+ def get_routing_protocol(self) -> Protocol:
192
+ """Method to get the routing protocol in the network manager.
193
+
194
+ Returns:
195
+ Protocol: the routing protocol in the network manager
196
+ """
197
+ return self.routing_protocol
198
+
169
199
 
170
- def NewNetworkManager(owner: "QuantumRouter", memory_array_name: str) -> "NetworkManager":
200
+ def NewNetworkManager(owner: "QuantumRouter", memory_array_name: str, component_templates: dict = {}) -> "NetworkManager":
171
201
  """Function to create a new network manager.
172
202
 
173
203
  Will create a network manager with default protocol stack.
@@ -176,16 +206,27 @@ def NewNetworkManager(owner: "QuantumRouter", memory_array_name: str) -> "Networ
176
206
  Args:
177
207
  owner (QuantumRouter): node to attach network manager to.
178
208
  memory_array_name (str): name of the memory array component on owner.
209
+ routing_protocol_cls (type[Protocol]): routing protocol class to use for control plane.
179
210
 
180
211
  Returns:
181
212
  NetworkManager: network manager object created.
182
213
  """
183
214
  swapping_success_rate = 0.5
184
215
  manager = NetworkManager(owner, [])
185
- routing = StaticRoutingProtocol(owner, owner.name + ".StaticRoutingProtocol", {})
216
+ routing = component_templates.get("routing", "static")
217
+ match routing:
218
+ case "static":
219
+ routing_protocol_cls = StaticRoutingProtocol
220
+ case "distributed":
221
+ routing_protocol_cls = DistributedRoutingProtocol
222
+ case _:
223
+ raise NotImplementedError(f"Routing protocol {routing} not implemented.")
224
+ routing = routing_protocol_cls(owner, f"{routing_protocol_cls.__name__}")
225
+ manager.set_routing_protocol(routing)
226
+ forwarding_protocol = ForwardingProtocol(owner, owner.name + ".ForwardingProtocol")
186
227
  rsvp = ResourceReservationProtocol(owner, owner.name + ".RSVP", memory_array_name)
187
228
  rsvp.set_swapping_success_rate(swapping_success_rate)
188
- routing.upper_protocols.append(rsvp)
189
- rsvp.lower_protocols.append(routing)
190
- manager.load_stack([routing, rsvp])
229
+ forwarding_protocol.upper_protocols.append(rsvp)
230
+ rsvp.lower_protocols.append(forwarding_protocol)
231
+ manager.load_stack([forwarding_protocol, rsvp])
191
232
  return manager
@@ -101,7 +101,7 @@ def eg_req_func(protocols: list["EntanglementProtocol"], args: Arguments) -> Ent
101
101
  Args:
102
102
  protocols: the waiting protocols (wait for request)
103
103
  args: arguments from the node who sent the request
104
- Return:
104
+ Returns:
105
105
  the selected protocol
106
106
  """
107
107
  name = args["name"]
@@ -155,7 +155,7 @@ def ep_req_func1(protocols, args: Arguments) -> BBPSSWProtocol:
155
155
  Args:
156
156
  protocols (list): a list of waiting protocols
157
157
  args (dict): the arguments
158
- Return:
158
+ Returns:
159
159
  the selected protocol
160
160
  """
161
161
  remote0 = args["remote0"]
@@ -268,7 +268,7 @@ def es_req_func(protocols: list["EntanglementProtocol"], args: Arguments) -> Ent
268
268
  Args:
269
269
  protocols (list): a list of waiting protocols
270
270
  args (dict): the arguments
271
- Return:
271
+ Returns:
272
272
  the selected protocol
273
273
  """
274
274
  target_memo = args["target_memo"]
@@ -472,7 +472,7 @@ class ResourceReservationProtocol(StackProtocol):
472
472
 
473
473
  Args:
474
474
  path (list[str]): a list of router names that goes from initiator to responder
475
- Return:
475
+ Returns:
476
476
  str: the name of the next hop
477
477
  '''
478
478
  cur_index = path.index(self.owner.name)