network.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import netsquid as ns
  2. import numpy as np
  3. from netsquid.nodes import Node
  4. from netsquid.protocols import NodeProtocol
  5. from nb_protocol import NBProtocolAlice, NBProtocolBob
  6. from utils import EntanglingConnectionOnDemand, create_qprocessor
  7. class BAI:
  8. '''The base class of the Best Arm Identification algorithm.'''
  9. def __init__(self, arms):
  10. self.arms = arms
  11. class QuantumNode(Node):
  12. '''A quantum node with a quantum port and quantum memory.'''
  13. def __init__(self, name):
  14. super().__init__(name)
  15. # For our purpose, we only need to store 1 qubit
  16. self.qmemory = create_qprocessor(num_positions=1)
  17. # Add quantum port used for receiving qubits generated by quantum source
  18. self.add_ports(["qport"])
  19. class QuantumNodeProtocol(NodeProtocol):
  20. '''The protocol of each quantum node
  21. It scans the quantum port and see whether there is an input
  22. If yes, it stores the qubit in the node's quantum memory
  23. '''
  24. def run(self):
  25. while True:
  26. qport = self.node.ports["qport"]
  27. yield self.await_port_input(qport)
  28. msg = qport.rx_input()
  29. if msg is not None:
  30. self.node.qmemory.put(msg.items[0])
  31. class QuantumNetwork:
  32. '''Simulate the quantum links between two parties, Alice and Bob.
  33. '''
  34. def __init__(self, path_num, fidelity_list, noise_model):
  35. '''Initialize `path_num` number of paths between Alice and Bob.
  36. The fidelity of each path is provided in `fidelity_list`.
  37. '''
  38. super().__init__()
  39. assert path_num == len(fidelity_list)
  40. self.best_path = np.argmax(fidelity_list) + 1
  41. self.noise_model = noise_model
  42. # Initialize Alice and Bob
  43. self.alice = QuantumNode(name="Alice")
  44. self.bob = QuantumNode(name="Bob")
  45. alice_protocol = QuantumNodeProtocol(self.alice)
  46. bob_protocol = QuantumNodeProtocol(self.bob)
  47. alice_protocol.start()
  48. bob_protocol.start()
  49. # Initialize quantum channels between Alice and Bob
  50. # Note that the channels are not connected to Alice and Bob yet
  51. self.quantum_channels = []
  52. for i in range(path_num):
  53. qconn = EntanglingConnectionOnDemand(noise_model, fidelity=fidelity_list[i])
  54. self.quantum_channels.append(qconn)
  55. def benchmark_path(self, path, bounces, sample_times):
  56. """Run network benchmarking along `path`.
  57. Parameters
  58. ----------
  59. path :int
  60. Path id
  61. bounces : [int]
  62. List of number of bounces
  63. sample_times : dict, int -> int
  64. Map from number of bounces to its repetition times
  65. """
  66. # Get the quantum channel of the corresponding path
  67. qconn = self.quantum_channels[path - 1]
  68. # print("Benchmarking channel with fidelity:", qconn.fidelity)
  69. # Connect Alice and Bob via the quantum channel
  70. self.alice.ports["qport"].disconnect()
  71. self.bob.ports["qport"].disconnect()
  72. self.alice.ports["qport"].connect(qconn.ports["A"])
  73. self.bob.ports["qport"].connect(qconn.ports["B"])
  74. while True:
  75. # Run NB protocol using quantum channel `qconn`
  76. alice_protocol = NBProtocolAlice(self.alice, bounce=bounces, num_samples=sample_times, qconn=qconn)
  77. bob_protocol = NBProtocolBob(self.bob)
  78. # Let Alice and Bob know each other
  79. alice_protocol.set_target_protocol(bob_protocol)
  80. bob_protocol.set_target_protocol(alice_protocol)
  81. alice_protocol.start()
  82. bob_protocol.start()
  83. ns.sim_run()
  84. p, cost = alice_protocol.data_processing()
  85. # print(f"Estimated parameter p: {p}, cost: {cost}")
  86. # Only accept the result if the estimated parameter is in a reasonable range
  87. if p >= 0 and p < 1.5:
  88. return p, cost