Youngjoon Lee 3d14319588
Targeted experiments for queuing mechanism
Targeted experiments for queuing mechanism

gather series into dataframe

put exp_id to the CSV path

revert iterations back to num_nodes/2

add missing print and decrease msg_interval_sec

change param sequence for readability

use struct instead of pickle for fixed-size & faster serde

include dtime series into dataframe

optimize: choose optimized connection type according to latency setting

add skip_sending_noise option

optimize filling up the queue with noises

move queue_type to the end of param set, and build CSV gradually row by row

fix: consider num_senders when waiting until all messages are disseminated

fix: sample senders without duplicate

fix: build param combinations correctly

add plot script

initialize MinSizeMixQueue with noises

define SessionParameterSet and add paramset for session2

improve topology connectivity check to avoid "maxmimum recursions depth exceeded" error

fix: the correct parameter set constructor

store individual series to separate CSV files

reorganize files and draw plot automatically

start series file id from 1 (not 0)

add queue_type CLI argument for parallelization

pretty format of elapsed time

pretty format of elapsed time

add merge CLI and draw multiple plots

split functions

do not draw plot for each session

use concurrent.futures to utilize multiprocessing

add from_paramset argument

fix: count num of finished iterations correctly

draw plots for num_sent_msgs and num_senders for specific experiments
2024-08-02 11:38:17 +09:00

63 lines
2.2 KiB
Python

from __future__ import annotations
import random
from collections import defaultdict
from protocol.node import Node
Topology = dict[int, set[int]]
def build_full_random_topology(
rng: random.Random, num_nodes: int, peering_degree: int
) -> Topology:
"""
Generate a random undirected topology until all nodes are connected.
We don't implement any artificial tool to ensure the connectivity of the topology.
Instead, we regenerate a topology in a fully randomized way until all nodes are connected.
"""
while True:
topology: Topology = defaultdict(set[int])
nodes = list(range(num_nodes))
for node in nodes:
# Filter nodes that can be connected to the current node.
others = []
for other in nodes[:node] + nodes[node + 1 :]:
# Check if the other node is not already connected to the current node
# and the other node has not reached the peering degree.
if (
other not in topology[node]
and len(topology[other]) < peering_degree
):
others.append(other)
# How many more connections the current node needs
n_needs = peering_degree - len(topology[node])
# Sample peers as many as possible
peers = rng.sample(others, k=min(n_needs, len(others)))
# Connect the current node to the peers
topology[node].update(peers)
# Connect the peers to the current node, since the topology is undirected
for peer in peers:
topology[peer].update([node])
if are_all_nodes_connected(topology):
return topology
def are_all_nodes_connected(topology: Topology) -> bool:
visited = dfs(topology, next(iter(topology)))
return len(visited) == len(topology)
def dfs(topology: Topology, start_node: int) -> set[int]:
visited: set[int] = set()
stack = [start_node]
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
stack.extend(peer for peer in topology[node] if peer not in visited)
return visited