Routing with Entanglement¶
In this example, we see how to add a custom routing function that considers the entanglement in the network.
We configure the network as follows:
1 2 | A <==> node_1; A <==> node_2
B <==> node_1; B <==> node_2
|
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 | nodes = ['A', 'node_1', 'node_2', 'B']
network.use_hop_by_hop = False
network.set_delay = 0.1
network.start(nodes)
A = Host('A')
A.add_connection('node_1')
A.add_connection('node_2')
A.start()
node_1 = Host('node_1')
node_1.add_connection('A')
node_1.add_connection('B')
node_1.start()
node_2 = Host('node_2')
node_2.add_connection('A')
node_2.add_connection('B')
node_2.start()
B = Host('B')
B.add_connection('node_1')
B.add_connection('node_2')
B.start()
hosts = [A, node_1, node_2, B]
for h in hosts:
network.add_host(h)
|
We add a protocol for a Host to constantly generate entanglement.
1 2 3 4 5 6 7 8 9 10 11 12 13 | def generate_entanglement(host):
"""
Generate entanglement if the host has nothing to process (i.e. is idle).
"""
while True:
if host.is_idle():
host_connections = host.get_connections()
for connection in host_connections:
if connection['type'] == 'quantum':
num_epr_pairs = len(host.get_epr_pairs(connection['connection']))
if num_epr_pairs < 4:
host.send_epr(connection['connection'], await_ack=True)
time.sleep(5)
|
The routing algorithm works as follows.
Build a graph with the vertices the Hosts and the edges the connections
The weight of each edge is the inverse of the amount of entanglement shared on that link (using a shortest path works best with networkx)
When there is no entanglement then add a large weight to that edge
Compute the shortest path on this newly generated graph from sender to receiver and return the route
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 | def routing_algorithm(di_graph, source, target):
"""
Entanglement based routing function. Note: any custom routing function must
have exactly these three parameters and must return a list ordered by the steps
in the route.
Args:
di_graph (networkx DiGraph): The directed graph representation of the network.
source (str): The sender ID
target (str: The receiver ID
Returns:
(list): The route ordered by the steps in the route.
"""
entanglement_network = nx.DiGraph()
nodes = di_graph.nodes()
# Generate entanglement network
for node in nodes:
host = network.get_host(node)
host_connections = host.get_connections()
for connection in host_connections:
if connection['type'] == 'quantum':
num_epr_pairs = len(host.get_epr_pairs(connection['connection']))
if num_epr_pairs == 0:
entanglement_network.add_edge(host.host_id, connection['connection'], weight=1000)
else:
entanglement_network.add_edge(host.host_id, connection['connection'], weight=1. / num_epr_pairs)
try:
route = nx.shortest_path(entanglement_network, source, target, weight='weight')
print('-------' + str(route) + '-------')
return route
except Exception as e:
Logger.get_instance().error(e)
|
To test the routing, we send superdense messages from A to B after we allow the network to build up some entanglement
1 2 3 4 5 6 7 8 9 10 11 12 13 | node_1.run_protocol(generate_entanglement)
node_2.run_protocol(generate_entanglement)
print('---- BUILDING ENTANGLEMENT ----')
# Let the network build up entanglement
time.sleep(15)
print('---- DONE BUILDING ENTANGLEMENT ----')
choices = ['00', '11', '10', '01']
for _ in range(5):
print('---- sending superdense ----')
A.send_superdense(B.host_id, random.choice(choices), await_ack=True)
time.sleep(1)
|
The full example is below.
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 | from qunetsim.components import Host
from qunetsim.components import Network
from qunetsim.objects import Logger
import networkx
import time
def generate_entanglement(host):
"""
Generate entanglement if the host has nothing to process (i.e. is idle).
"""
while True:
if host.is_idle():
host_connections = host.get_connections()
for connection in host_connections:
if connection['type'] == 'quantum':
num_epr_pairs = len(host.get_epr_pairs(connection['connection']))
if num_epr_pairs < 4:
host.send_epr(connection['connection'], await_ack=True)
time.sleep(5)
def routing_algorithm(di_graph, source, target):
"""
Entanglement based routing function. Note: any custom routing function must
have exactly these three parameters and must return a list ordered by the steps
in the route.
Args:
di_graph (networkx DiGraph): The directed graph representation of the network.
source (str): The sender ID
target (str: The receiver ID
Returns:
(list): The route ordered by the steps in the route.
"""
# Generate entanglement network
entanglement_network = nx.DiGraph()
nodes = di_graph.nodes()
for node in nodes:
host = network.get_host(node)
host_connections = host.get_connections()
for connection in host_connections:
if connection['type'] == 'quantum':
num_epr_pairs = len(host.get_epr_pairs(connection['connection']))
if num_epr_pairs == 0:
entanglement_network.add_edge(host.host_id, connection['connection'], weight=1000)
else:
entanglement_network.add_edge(host.host_id, connection['connection'], weight=1. / num_epr_pairs)
try:
route = nx.shortest_path(entanglement_network, source, target, weight='weight')
print('-------' + str(route) + '-------')
return route
except Exception as e:
Logger.get_instance().error(e)
def main():
network = Network.get_instance()
network.quantum_routing_algo = routing_algorithm
nodes = ['A', 'node_1', 'node_2', 'B']
network.use_hop_by_hop = False
network.set_delay = 0.2
network.start(nodes)
A = Host('A')
A.add_connection('node_1')
A.add_connection('node_2')
A.start()
node_1 = Host('node_1')
node_1.add_connection('A')
node_1.add_connection('B')
node_1.start()
node_2 = Host('node_2')
node_2.add_connection('A')
node_2.add_connection('B')
node_2.start()
B = Host('B')
B.add_connection('node_1')
B.add_connection('node_2')
B.start()
hosts = [A, node_1, node_2, B]
for h in hosts:
network.add_host(h)
node_1.run_protocol(generate_entanglement)
node_2.run_protocol(generate_entanglement)
print('---- BUILDING ENTANGLEMENT ----')
# Let the network build up entanglement
time.sleep(15)
print('---- DONE BUILDING ENTANGLEMENT ----')
choices = ['00', '11', '10', '01']
for _ in range(5):
print('---- sending superdense ----')
A.send_superdense(B.host_id, random.choice(choices), await_ack=True)
time.sleep(1)
# Let the network run for 40 seconds
time.sleep(40)
print('stopping')
network.stop(stop_hosts=True)
|