def test_completion_detection(): """ Tests that the completeness of an embedding is accurately detected in a simple example. """ infra = InfrastructureNetwork() # One source, one sink, one relay. # Enough transmit power so that it doesn't need to be taken into account nsource = infra.add_source( pos=(0, 0), # transmit power should not block anything in this example transmit_power_dbm=100, ) _nrelay = infra.add_intermediate(pos=(0, 1), transmit_power_dbm=100) nsink = infra.set_sink(pos=(1, 1), transmit_power_dbm=100) overlay = OverlayNetwork() esource = ENode(overlay.add_source(), nsource) esink = ENode(overlay.set_sink(), nsink) overlay.add_link(esource.block, esink.block) embedding = PartialEmbedding( infra, overlay, source_mapping=[(esource.block, esource.node)] ) assert not embedding.is_complete() embedding.take_action(esource, esink, 0) assert embedding.is_complete()
def test_count_timeslots_loop(): """Tests reasonable counting behaviour with loops""" infra = InfrastructureNetwork() # One source, one sink, two intermediates nsource = infra.add_source(pos=(0, 0), transmit_power_dbm=30, name="nso") ninterm1 = infra.add_intermediate( pos=(2, 1), transmit_power_dbm=5, name="ni1" ) ninterm2 = infra.add_intermediate( pos=(0, -1), transmit_power_dbm=5, name="ni2" ) nsink = infra.set_sink(pos=(2, 0), transmit_power_dbm=30, name="nsi") overlay = OverlayNetwork() esource = ENode(overlay.add_source(name="bso"), nsource) einterm1 = ENode(overlay.add_intermediate(name="bi1"), ninterm1) einterm2 = ENode(overlay.add_intermediate(name="bi2"), ninterm2) esink = ENode(overlay.set_sink(name="bsi"), nsink) overlay.add_link(esource.block, einterm1.block) overlay.add_link(einterm1.block, esink.block) overlay.add_link(esink.block, einterm2.block) overlay.add_link(einterm2.block, esource.block) embedding = PartialEmbedding( infra, overlay, source_mapping=[(esource.block, esource.node)] ) assert not embedding.is_complete() assert embedding.used_timeslots == 0 assert embedding.take_action(esource, einterm1, 0) assert not embedding.is_complete() assert embedding.used_timeslots == 1 assert embedding.take_action(einterm1, esink, 1) assert not embedding.is_complete() assert embedding.used_timeslots == 2 assert embedding.take_action(esink, einterm2, 2) assert not embedding.is_complete() assert embedding.used_timeslots == 3 assert embedding.take_action(einterm2, esource, 1) assert embedding.is_complete() assert embedding.used_timeslots == 3
def test_count_timeslots_parallel(): """Tests correct counting behaviour with parallel connections""" infra = InfrastructureNetwork() # One source, one sink, two intermediates nsource = infra.add_source( pos=(0, 0), transmit_power_dbm=30, name="nsource" ) ninterm1 = infra.add_intermediate( pos=(1, 2), transmit_power_dbm=30, name="ninterm1" ) ninterm2 = infra.add_intermediate( pos=(1, -2), transmit_power_dbm=30, name="ninterm2" ) nsink = infra.set_sink(pos=(2, 0), transmit_power_dbm=30, name="nsink") overlay = OverlayNetwork() esource = ENode(overlay.add_source(name="bsource"), nsource) einterm1 = ENode(overlay.add_intermediate(name="binterm1"), ninterm1) einterm2 = ENode(overlay.add_intermediate(name="binterm2"), ninterm2) esink = ENode(overlay.set_sink(name="bsink"), nsink) # fork overlay.add_link(esource.block, einterm1.block) overlay.add_link(esource.block, einterm2.block) overlay.add_link(einterm1.block, esink.block) overlay.add_link(einterm2.block, esink.block) embedding = PartialEmbedding( infra, overlay, source_mapping=[(esource.block, esource.node)] ) assert not embedding.is_complete() assert embedding.used_timeslots == 0 assert embedding.take_action(esource, einterm1, 0) assert embedding.take_action(esource, einterm2, 0) assert not embedding.is_complete() assert embedding.used_timeslots == 1 assert embedding.take_action(einterm1, esink, 1) assert not embedding.is_complete() assert embedding.used_timeslots == 2 assert embedding.take_action(einterm2, esink, 2) assert embedding.is_complete() assert embedding.used_timeslots == 3
def test_loop_within_infra_possible(): """ Tests that a loop within the infrastructure is always possible and does not interfere with other connections. This can be used to embed multiple consecutive blocks within one node. """ infra = InfrastructureNetwork() nsource = infra.add_source(pos=(0, 0), transmit_power_dbm=30, name="nso") nsink = infra.set_sink(pos=(1, 0), transmit_power_dbm=30, name="nsi") overlay = OverlayNetwork() esource = ENode(overlay.add_source(name="bso"), nsource) einterm = ENode(overlay.add_intermediate(name="bin"), nsource) esink = ENode(overlay.set_sink(name="bsi"), nsink) overlay.add_link(esource.block, einterm.block) overlay.add_link(einterm.block, esink.block) embedding = PartialEmbedding( infra, overlay, source_mapping=[(esource.block, esource.node)] ) sinr_before = embedding.known_sinr(nsource, nsink, 0) assert embedding.take_action(esource, einterm, 0) sinr_after = embedding.known_sinr(nsource, nsink, 0) assert sinr_before == sinr_after assert embedding.take_action(einterm, esink, 0) assert embedding.is_complete()
def test_count_timeslots_multiple_sources(): """Tests correct counting behaviour with multiple sources""" infra = InfrastructureNetwork() nsource1 = infra.add_source(pos=(0, -1), transmit_power_dbm=30) nsource2 = infra.add_source(pos=(0, 1), transmit_power_dbm=30) nsink = infra.set_sink(pos=(1, 0), transmit_power_dbm=30) overlay = OverlayNetwork() esource1 = ENode(overlay.add_source(), nsource1) esource2 = ENode(overlay.add_source(), nsource2) esink = ENode(overlay.set_sink(), nsink) overlay.add_link(esource1.block, esink.block) overlay.add_link(esource2.block, esink.block) embedding = PartialEmbedding( infra, overlay, source_mapping=[ (esource1.block, esource1.node), (esource2.block, esource2.node), ], ) assert not embedding.is_complete() assert embedding.used_timeslots == 0 assert embedding.take_action(esource1, esink, 0) assert not embedding.is_complete() assert embedding.used_timeslots == 1 assert embedding.take_action(esource2, esink, 1) assert embedding.is_complete() assert embedding.used_timeslots == 2
def draw_embedding( embedding: PartialEmbedding, sources_color="red", sink_color="yellow", intermediates_color="green", ): """Draws a given PartialEmbedding""" g = embedding.graph shared_args = { "G": g, "node_size": 1000, "pos": nx.shell_layout(embedding.graph), } node_list = g.nodes() chosen = [node for node in node_list if g.nodes[node]["chosen"]] not_chosen = [node for node in node_list if not g.nodes[node]["chosen"]] def kind_color(node): kind = g.nodes[node]["kind"] color = intermediates_color if kind == "source": color = sources_color elif kind == "sink": color = sink_color return color nx.draw_networkx_nodes( nodelist=not_chosen, node_color=list(map(kind_color, not_chosen)), node_shape="o", **shared_args, ) nx.draw_networkx_nodes( nodelist=chosen, node_color=list(map(kind_color, chosen)), node_shape="s", **shared_args, ) nx.draw_networkx_labels(**shared_args) possibilities = embedding.possibilities() def chosen_color(edge): data = g.edges[edge] chosen = data["chosen"] (source, target, _) = edge if (source, target, data["timeslot"]) in possibilities: return "blue" if chosen: return "black" return "gray" def chosen_width(edge): data = g.edges[edge] (source, target, _) = edge chosen = data["chosen"] possible = (source, target, data["timeslot"]) in possibilities if chosen: return 2 if possible: return 1 return 0.1 edgelist = g.edges(keys=True) nx.draw_networkx_edges( **shared_args, edgelist=edgelist, edge_color=list(map(chosen_color, edgelist)), width=list(map(chosen_width, edgelist)), ) chosen_edges = [edge for edge in edgelist if g.edges[edge]["chosen"]] # Networkx doesn't really deal with drawing multigraphs very well. # Luckily for our presentation purposes its enough to pretend the # graph isn't a multigraph, so throw away the edge keys. labels = {(u, v): g.edges[(u, v, k)]["timeslot"] for (u, v, k) in chosen_edges} nx.draw_networkx_edge_labels(**shared_args, edgelist=chosen_edges, edge_labels=labels) timeslots = embedding.used_timeslots complete = embedding.is_complete() complete_str = " (complete)" if complete else "" plt.gca().text( -1, -1, f"{timeslots} timeslots{complete_str}", bbox=dict(boxstyle="round", facecolor="wheat", alpha=0.5), )