import unittest
from inspect import isclass
from math import inf as Inf
from pydistsim.demo_algorithms.readsensors import ReadSensors
from pydistsim.network import NetworkGenerator, NetworkGeneratorException, UdgRangeType
from pydistsim.network.environment import Environment2D
from pydistsim.network.network import NetworkType
from pydistsim.utils.testing import PyDistSimTestCase
[docs]
class TestNetworkGeneration(PyDistSimTestCase):
[docs]
def setUp(self):
# Raises NetworkGeneratorException
# returns None
# else expected network/node properties dictionary
env = Environment2D(shape=(600, 600))
rangeType = UdgRangeType(env)
algorithms = (ReadSensors,)
self.in_out = [
(
"default N_COUNT and COMM_RANGE and ENVIRONMENT should be compatible",
{
"n_count": None,
"n_min": 0,
"n_max": Inf,
"enforce_connected": True,
"environment": None,
"degree": None,
"comm_range": None,
},
{"count": list(range(100, 1001))},
),
(
"regular default params",
{
"n_count": 100,
"n_min": 0,
"n_max": Inf,
"enforce_connected": True,
"environment": env,
"degree": None,
"comm_range": 100,
},
{"count": list(range(100, 1001))},
),
############## connected True degree False
(
"increase node number",
{
"n_count": 10,
"n_min": 0,
"n_max": Inf,
"enforce_connected": True,
"environment": env,
"degree": None,
"comm_range": 100,
},
{"count": list(range(11, 301))},
),
(
"increase commRange",
{
"n_count": 10,
"n_min": 0,
"n_max": 10,
"enforce_connected": True,
"environment": env,
"degree": None,
"comm_range": None,
},
{"count": 10},
),
(
"decrease commRange",
{
"n_count": 10,
"n_min": 10,
"n_max": 10,
"enforce_connected": True,
"environment": env,
"degree": 0,
"comm_range": None,
},
{"count": 10},
),
############## connected True degree True
(
"increase node number",
{
"n_count": 10,
"n_min": 0,
"n_max": 200,
"enforce_connected": True,
"environment": env,
"degree": 11,
"comm_range": 100,
},
{"count": list(range(10, 201))},
),
(
"increase commRange",
{
"n_count": 10,
"n_min": 0,
"n_max": 10,
"enforce_connected": True,
"environment": env,
"degree": 9,
"degree_tolerance": 0.01,
"comm_range": None,
},
{"count": 10},
),
(
"low degree with connected, alternating directions problem",
{
"n_count": 10,
"n_min": 0,
"n_max": 10,
"enforce_connected": True,
"environment": env,
"degree": 3,
"comm_range": 30,
},
None,
),
############## connected False degree True
(
"increase node number",
{
"n_count": 10,
"n_min": 0,
"n_max": 200,
"enforce_connected": False,
"environment": env,
"degree": 8,
"comm_range": 100,
},
{"count": list(range(10, 201))},
),
(
"increase commRange",
{
"n_count": 10,
"n_min": 0,
"n_max": 200,
"enforce_connected": False,
"environment": env,
"degree": 11,
"comm_range": None,
},
{"count": list(range(10, 201))},
),
(
"low degree",
{
"n_count": 10,
"n_min": 0,
"n_max": 100,
"enforce_connected": False,
"environment": env,
"degree": 3,
"comm_range": 100,
},
{"count": list(range(10, 101))},
),
(
"degree too high for node number",
{
"n_count": 10,
"n_min": 0,
"n_max": 10,
"enforce_connected": False,
"environment": env,
"degree": 10,
"comm_range": None,
},
NetworkGeneratorException,
),
(
"",
{
"n_count": 11,
"n_min": 0,
"n_max": 10,
"enforce_connected": False,
"environment": env,
"degree": None,
"comm_range": None,
},
NetworkGeneratorException,
),
(
"",
{
"n_count": 9,
"n_min": 10,
"n_max": 10,
"enforce_connected": False,
"environment": env,
"degree": None,
"comm_range": None,
},
NetworkGeneratorException,
),
############## connected False degree False - no need for modifying initially created network
# also remove environment from kwargs to test default and change comm_range to commRange
(
"",
{
"n_count": 10,
"n_min": 0,
"n_max": 100,
"enforce_connected": False,
"degree": None,
"commRange": 100,
},
{"count": 10},
),
(
"",
{
"n_count": 20,
"n_min": 0,
"n_max": 100,
"enforce_connected": False,
"degree": None,
"commRange": None,
},
{"count": 20},
),
(
"",
{
"n_count": 30,
"n_min": 0,
"n_max": 100,
"enforce_connected": False,
"degree": None,
"commRange": 30,
},
{"count": 30},
),
(
"Check sensors and algorithms",
{
"n_count": 10,
"n_min": 0,
"n_max": 100,
"enforce_connected": False,
"rangeType": rangeType,
"algorithms": algorithms,
"commRange": 100,
},
{
"count": 10,
"rangeType": rangeType,
"algorithms": algorithms,
"commRange": 100,
},
),
]
[docs]
def test_random_generation(self):
"""Test different random generation parameters"""
for comment, input, output in self.in_out:
for directed in (True, False):
with self.subTest(input=input, output=output, directed=directed):
print(f"{comment=}")
print(f"{input=}\n{output=}")
if isclass(output) and issubclass(output, Exception):
self.assertRaises(output, NetworkGenerator, **input)
continue
net_gen = NetworkGenerator(directed=directed, **input)
if output is None:
self.assertEqual(None, net_gen.generate_random_network(max_steps=500))
elif isinstance(output, dict):
net = net_gen.generate_random_network(max_steps=2000)
assert isinstance(net, NetworkType)
assert directed == net.is_directed()
net.validate_params(output)
[docs]
class TestNotConnectedNetworkGeneration(unittest.TestCase):
[docs]
def setUp(self) -> None:
self.gen = NetworkGenerator(
n_count=10,
n_min=10,
n_max=10,
degree=0.01,
degree_tolerance=0.2,
enforce_connected=False,
)
def test_generate_not_connected_net(self):
for directed in (True, False):
with self.subTest(directed=directed):
self.gen.directed = directed
net = self.gen.generate_random_network()
assert not net.is_connected()
assert len(net) == 10
assert abs(net.avg_degree()) <= 0.2
assert net.is_directed() == directed
[docs]
class TestOtherGenerators(unittest.TestCase):
[docs]
def setUp(self) -> None:
self.gen1 = NetworkGenerator(n_count=10, n_min=0, n_max=100, enforce_connected=True)
self.gen2 = NetworkGenerator(n_count=10, n_min=10, n_max=10, enforce_connected=True)
self.gen3 = NetworkGenerator(n_count=99, n_min=99, n_max=99, enforce_connected=True)
self.gen4 = NetworkGenerator(
n_count=10,
n_min=10,
n_max=10,
degree=0,
degree_tolerance=0.2,
enforce_connected=False,
)
def test_generate_neighborhood(self):
net1 = self.gen1.generate_neigborhood_network()
assert len(net1) >= 10 and len(net1) <= 100
assert net1.is_connected()
net2 = self.gen2.generate_neigborhood_network()
assert len(net2) == 10
assert net2.is_connected()
net3 = self.gen3.generate_neigborhood_network()
assert len(net3) == 99
assert net3.is_connected()
# Dont test for the connectedness and degree for this network
# as it is not enforced
def test_homogeneous_network(self):
net1 = self.gen1.generate_homogeneous_network()
assert len(net1) >= 10 and len(net1) <= 100
assert net1.is_connected()
net2 = self.gen2.generate_homogeneous_network()
assert len(net2) == 10
assert net2.is_connected()
net3 = self.gen3.generate_homogeneous_network()
assert len(net3) == 99
assert net3.is_connected()
net4 = self.gen4.generate_homogeneous_network()
assert len(net4) == 10
assert not net4.is_connected()
assert abs(net4.avg_degree()) <= 0.2