| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- import netsquid as ns
- import numpy as np
- from netsquid.nodes import Node
- from netsquid.protocols import NodeProtocol
- from nb_protocol import NBProtocolAlice, NBProtocolBob
- from utils import EntanglingConnectionOnDemand, create_qprocessor
- class BAI:
- '''The base class of the Best Arm Identification algorithm.'''
- def __init__(self, arms):
- self.arms = arms
- class QuantumNode(Node):
- '''A quantum node with a quantum port and quantum memory.'''
- def __init__(self, name):
- super().__init__(name)
- # For our purpose, we only need to store 1 qubit
- self.qmemory = create_qprocessor(num_positions=1)
- # Add quantum port used for receiving qubits generated by quantum source
- self.add_ports(["qport"])
- class QuantumNodeProtocol(NodeProtocol):
- '''The protocol of each quantum node
- It scans the quantum port and see whether there is an input
- If yes, it stores the qubit in the node's quantum memory
- '''
- def run(self):
- while True:
- qport = self.node.ports["qport"]
- yield self.await_port_input(qport)
- msg = qport.rx_input()
- if msg is not None:
- self.node.qmemory.put(msg.items[0])
- class QuantumNetwork:
- '''Simulate the quantum links between two parties, Alice and Bob.
- '''
- def __init__(self, path_num, fidelity_list, noise_model):
- '''Initialize `path_num` number of paths between Alice and Bob.
- The fidelity of each path is provided in `fidelity_list`.
- '''
- super().__init__()
- assert path_num == len(fidelity_list)
- self.best_path = np.argmax(fidelity_list) + 1
- self.noise_model = noise_model
- # Initialize Alice and Bob
- self.alice = QuantumNode(name="Alice")
- self.bob = QuantumNode(name="Bob")
- alice_protocol = QuantumNodeProtocol(self.alice)
- bob_protocol = QuantumNodeProtocol(self.bob)
- alice_protocol.start()
- bob_protocol.start()
- # Initialize quantum channels between Alice and Bob
- # Note that the channels are not connected to Alice and Bob yet
- self.quantum_channels = []
- for i in range(path_num):
- qconn = EntanglingConnectionOnDemand(noise_model, fidelity=fidelity_list[i])
- self.quantum_channels.append(qconn)
- def benchmark_path(self, path, bounces, sample_times):
- """Run network benchmarking along `path`.
- Parameters
- ----------
- path :int
- Path id
- bounces : [int]
- List of number of bounces
- sample_times : dict, int -> int
- Map from number of bounces to its repetition times
- """
- # Get the quantum channel of the corresponding path
- qconn = self.quantum_channels[path - 1]
- # print("Benchmarking channel with fidelity:", qconn.fidelity)
- # Connect Alice and Bob via the quantum channel
- self.alice.ports["qport"].disconnect()
- self.bob.ports["qport"].disconnect()
- self.alice.ports["qport"].connect(qconn.ports["A"])
- self.bob.ports["qport"].connect(qconn.ports["B"])
- while True:
- # Run NB protocol using quantum channel `qconn`
- alice_protocol = NBProtocolAlice(self.alice, bounce=bounces, num_samples=sample_times, qconn=qconn)
- bob_protocol = NBProtocolBob(self.bob)
- # Let Alice and Bob know each other
- alice_protocol.set_target_protocol(bob_protocol)
- bob_protocol.set_target_protocol(alice_protocol)
- alice_protocol.start()
- bob_protocol.start()
- ns.sim_run()
- p, cost = alice_protocol.data_processing()
- # print(f"Estimated parameter p: {p}, cost: {cost}")
- # Only accept the result if the estimated parameter is in a reasonable range
- if p >= 0 and p < 1.5:
- return p, cost
|