1
0
mirror of https://github.com/gsi-upm/soil synced 2025-08-24 03:52:20 +00:00

WIP: all tests pass

Documentation needs some improvement

The API has been simplified to only allow for ONE topology per
NetworkEnvironment.
This covers the main use case, and simplifies the code.
This commit is contained in:
J. Fernando Sánchez
2022-10-16 17:54:03 +02:00
parent cd62c23cb9
commit d9947c2c52
34 changed files with 693 additions and 736 deletions

View File

@@ -9,17 +9,16 @@ interval: 1
seed: "CompleteSeed!"
model_class: Environment
model_params:
topologies:
default:
params:
generator: complete_graph
n: 4
topology:
params:
generator: complete_graph
n: 4
agents:
agent_class: CounterModel
state:
group: network
times: 1
topology: 'default'
topology: true
distribution:
- agent_class: CounterModel
weight: 0.25
@@ -42,7 +41,7 @@ model_params:
fixed:
- agent_class: BaseAgent
hidden: true
topology: null
topology: false
state:
name: 'Environment Agent 1'
times: 10

View File

@@ -4,12 +4,14 @@ import pytest
from soil import agents, environment
from soil import time as stime
class Dead(agents.FSM):
@agents.default_state
@agents.state
def only(self):
return self.die()
class TestMain(TestCase):
def test_die_raises_exception(self):
d = Dead(unique_id=0, model=environment.Environment())
@@ -20,5 +22,5 @@ class TestMain(TestCase):
def test_die_returns_infinity(self):
d = Dead(unique_id=0, model=environment.Environment())
ret = d.step().abs(0)
print(ret, 'next')
print(ret, "next")
assert ret == stime.INFINITY

View File

@@ -7,9 +7,9 @@ from os.path import join
from soil import simulation, serialization, config, network, agents, utils
ROOT = os.path.abspath(os.path.dirname(__file__))
EXAMPLES = join(ROOT, '..', 'examples')
EXAMPLES = join(ROOT, "..", "examples")
FORCE_TESTS = os.environ.get('FORCE_TESTS', '')
FORCE_TESTS = os.environ.get("FORCE_TESTS", "")
def isequal(a, b):
@@ -24,7 +24,6 @@ def isequal(a, b):
class TestConfig(TestCase):
def test_conversion(self):
expected = serialization.load_file(join(ROOT, "complete_converted.yml"))[0]
old = serialization.load_file(join(ROOT, "old_complete.yml"))[0]
@@ -38,7 +37,7 @@ class TestConfig(TestCase):
The configuration should not change after running
the simulation.
"""
config = serialization.load_file(join(EXAMPLES, 'complete.yml'))[0]
config = serialization.load_file(join(EXAMPLES, "complete.yml"))[0]
s = simulation.from_config(config)
init_config = copy.copy(s.to_dict())
@@ -47,11 +46,8 @@ class TestConfig(TestCase):
# del nconfig['to
isequal(init_config, nconfig)
def test_topology_config(self):
netconfig = config.NetConfig(**{
'path': join(ROOT, 'test.gexf')
})
netconfig = config.NetConfig(**{"path": join(ROOT, "test.gexf")})
net = network.from_config(netconfig, dir_path=ROOT)
assert len(net.nodes) == 2
assert len(net.edges) == 1
@@ -62,36 +58,33 @@ class TestConfig(TestCase):
network agents are initialized properly.
"""
cfg = {
'name': 'CounterAgent',
'network_params': {
'path': join(ROOT, 'test.gexf')
},
'agent_class': 'CounterModel',
"name": "CounterAgent",
"network_params": {"path": join(ROOT, "test.gexf")},
"agent_class": "CounterModel",
# 'states': [{'times': 10}, {'times': 20}],
'max_time': 2,
'dry_run': True,
'num_trials': 1,
'environment_params': {
}
"max_time": 2,
"dry_run": True,
"num_trials": 1,
"environment_params": {},
}
conf = config.convert_old(cfg)
s = simulation.from_config(conf)
env = s.get_env()
assert len(env.topologies['default'].nodes) == 2
assert len(env.topologies['default'].edges) == 1
assert len(env.G.nodes) == 2
assert len(env.G.edges) == 1
assert len(env.agents) == 2
assert env.agents[0].G == env.topologies['default']
assert env.agents[0].G == env.G
def test_agents_from_config(self):
'''We test that the known complete configuration produces
the right agents in the right groups'''
"""We test that the known complete configuration produces
the right agents in the right groups"""
cfg = serialization.load_file(join(ROOT, "complete_converted.yml"))[0]
s = simulation.from_config(cfg)
env = s.get_env()
assert len(env.topologies['default'].nodes) == 4
assert len(env.agents(group='network')) == 4
assert len(env.agents(group='environment')) == 1
assert len(env.G.nodes) == 4
assert len(env.agents(group="network")) == 4
assert len(env.agents(group="environment")) == 1
def test_yaml(self):
"""
@@ -100,16 +93,17 @@ class TestConfig(TestCase):
Values not present in the original config file should have reasonable
defaults.
"""
with utils.timer('loading'):
config = serialization.load_file(join(EXAMPLES, 'complete.yml'))[0]
with utils.timer("loading"):
config = serialization.load_file(join(EXAMPLES, "complete.yml"))[0]
s = simulation.from_config(config)
with utils.timer('serializing'):
with utils.timer("serializing"):
serial = s.to_yaml()
with utils.timer('recovering'):
with utils.timer("recovering"):
recovered = yaml.load(serial, Loader=yaml.SafeLoader)
for (k, v) in config.items():
assert recovered[k] == v
def make_example_test(path, cfg):
def wrapped(self):
root = os.getcwd()
@@ -133,18 +127,19 @@ def make_example_test(path, cfg):
# assert env.now <= config['max_time'] # But not further than allowed
# except KeyError:
# pass
return wrapped
def add_example_tests():
for config, path in serialization.load_files(
join(EXAMPLES, '*', '*.yml'),
join(EXAMPLES, '*.yml'),
join(EXAMPLES, "*", "*.yml"),
join(EXAMPLES, "*.yml"),
):
p = make_example_test(path=path, cfg=config)
fname = os.path.basename(path)
p.__name__ = 'test_example_file_%s' % fname
p.__doc__ = '%s should be a valid configuration' % fname
p.__name__ = "test_example_file_%s" % fname
p.__doc__ = "%s should be a valid configuration" % fname
setattr(TestConfig, p.__name__, p)
del p

View File

@@ -5,9 +5,9 @@ from os.path import join
from soil import serialization, simulation, config
ROOT = os.path.abspath(os.path.dirname(__file__))
EXAMPLES = join(ROOT, '..', 'examples')
EXAMPLES = join(ROOT, "..", "examples")
FORCE_TESTS = os.environ.get('FORCE_TESTS', '')
FORCE_TESTS = os.environ.get("FORCE_TESTS", "")
class TestExamples(TestCase):
@@ -23,31 +23,31 @@ def make_example_test(path, cfg):
s.max_steps = 100
s.num_trials = 1
assert isinstance(cfg, config.Config)
if getattr(cfg, 'skip_test', False) and not FORCE_TESTS:
self.skipTest('Example ignored.')
if getattr(cfg, "skip_test", False) and not FORCE_TESTS:
self.skipTest("Example ignored.")
envs = s.run_simulation(dry_run=True)
assert envs
for env in envs:
assert env
try:
n = cfg.model_params['network_params']['n']
n = cfg.model_params["network_params"]["n"]
assert len(list(env.network_agents)) == n
except KeyError:
pass
assert env.schedule.steps > 0 # It has run
assert env.schedule.steps <= s.max_steps # But not further than allowed
return wrapped
def add_example_tests():
for cfg, path in serialization.load_files(
join(EXAMPLES, '*', '*.yml'),
join(EXAMPLES, '*.yml'),
join(EXAMPLES, "**", "*.yml"),
):
p = make_example_test(path=path, cfg=config.Config.from_raw(cfg))
fname = os.path.basename(path)
p.__name__ = 'test_example_file_%s' % fname
p.__doc__ = '%s should be a valid configuration' % fname
p.__name__ = "test_example_file_%s" % fname
p.__doc__ = "%s should be a valid configuration" % fname
setattr(TestExamples, p.__name__, p)
del p

View File

@@ -2,6 +2,7 @@ import os
import io
import tempfile
import shutil
import sqlite3
from unittest import TestCase
from soil import exporters
@@ -40,14 +41,10 @@ class Exporters(TestCase):
num_trials = 5
max_time = 2
config = {
'name': 'exporter_sim',
'model_params': {
'agents': [{
'agent_class': agents.BaseAgent
}]
},
'max_time': max_time,
'num_trials': num_trials,
"name": "exporter_sim",
"model_params": {"agents": [{"agent_class": agents.BaseAgent}]},
"max_time": max_time,
"num_trials": num_trials,
}
s = simulation.from_config(config)
@@ -64,40 +61,52 @@ class Exporters(TestCase):
assert Dummy.total_time == max_time * num_trials
def test_writing(self):
'''Try to write CSV, sqlite and YAML (without dry_run)'''
"""Try to write CSV, sqlite and YAML (without dry_run)"""
n_trials = 5
config = {
'name': 'exporter_sim',
'network_params': {
'generator': 'complete_graph',
'n': 4
},
'agent_class': 'CounterModel',
'max_time': 2,
'num_trials': n_trials,
'dry_run': False,
'environment_params': {}
"name": "exporter_sim",
"network_params": {"generator": "complete_graph", "n": 4},
"agent_class": "CounterModel",
"max_time": 2,
"num_trials": n_trials,
"dry_run": False,
"environment_params": {},
}
output = io.StringIO()
s = simulation.from_config(config)
tmpdir = tempfile.mkdtemp()
envs = s.run_simulation(exporters=[
exporters.default,
exporters.csv,
],
dry_run=False,
outdir=tmpdir,
exporter_params={'copy_to': output})
envs = s.run_simulation(
exporters=[
exporters.default,
exporters.csv,
],
model_params={
"agent_reporters": {"times": "times"},
"model_reporters": {
"constant": lambda x: 1,
},
},
dry_run=False,
outdir=tmpdir,
exporter_params={"copy_to": output},
)
result = output.getvalue()
simdir = os.path.join(tmpdir, s.group or '', s.name)
with open(os.path.join(simdir, '{}.dumped.yml'.format(s.name))) as f:
simdir = os.path.join(tmpdir, s.group or "", s.name)
with open(os.path.join(simdir, "{}.dumped.yml".format(s.name))) as f:
result = f.read()
assert result
try:
for e in envs:
with open(os.path.join(simdir, '{}.env.csv'.format(e.id))) as f:
db = sqlite3.connect(os.path.join(simdir, f"{e.id}.sqlite"))
cur = db.cursor()
agent_entries = cur.execute("SELECT * from agents").fetchall()
env_entries = cur.execute("SELECT * from env").fetchall()
assert len(agent_entries) > 0
assert len(env_entries) > 0
with open(os.path.join(simdir, "{}.env.csv".format(e.id))) as f:
result = f.read()
assert result
finally:

View File

@@ -6,60 +6,55 @@ import networkx as nx
from functools import partial
from os.path import join
from soil import (simulation, Environment, agents, network, serialization,
utils, config)
from soil import simulation, Environment, agents, network, serialization, utils, config
from soil.time import Delta
ROOT = os.path.abspath(os.path.dirname(__file__))
EXAMPLES = join(ROOT, '..', 'examples')
EXAMPLES = join(ROOT, "..", "examples")
class CustomAgent(agents.FSM, agents.NetworkAgent):
@agents.default_state
@agents.state
def normal(self):
self.neighbors = self.count_agents(state_id='normal',
limit_neighbors=True)
self.neighbors = self.count_agents(state_id="normal", limit_neighbors=True)
@agents.state
def unreachable(self):
return
class TestMain(TestCase):
def test_empty_simulation(self):
"""A simulation with a base behaviour should do nothing"""
config = {
'model_params': {
'network_params': {
'path': join(ROOT, 'test.gexf')
},
'agent_class': 'BaseAgent',
"model_params": {
"network_params": {"path": join(ROOT, "test.gexf")},
"agent_class": "BaseAgent",
}
}
s = simulation.from_config(config)
s.run_simulation(dry_run=True)
def test_network_agent(self):
"""
The initial states should be applied to the agent and the
agent should be able to update its state."""
config = {
'name': 'CounterAgent',
'num_trials': 1,
'max_time': 2,
'model_params': {
'network_params': {
'generator': nx.complete_graph,
'n': 2,
"name": "CounterAgent",
"num_trials": 1,
"max_time": 2,
"model_params": {
"network_params": {
"generator": nx.complete_graph,
"n": 2,
},
'agent_class': 'CounterModel',
'states': {
0: {'times': 10},
1: {'times': 20},
"agent_class": "CounterModel",
"states": {
0: {"times": 10},
1: {"times": 20},
},
}
},
}
s = simulation.from_config(config)
@@ -68,48 +63,41 @@ class TestMain(TestCase):
The initial states should be applied to the agent and the
agent should be able to update its state."""
config = {
'version': '2',
'name': 'CounterAgent',
'dry_run': True,
'num_trials': 1,
'max_time': 2,
'model_params': {
'topologies': {
'default': {
'path': join(ROOT, 'test.gexf')
}
"version": "2",
"name": "CounterAgent",
"dry_run": True,
"num_trials": 1,
"max_time": 2,
"model_params": {
"topology": {"path": join(ROOT, "test.gexf")},
"agents": {
"agent_class": "CounterModel",
"topology": True,
"fixed": [{"state": {"times": 10}}, {"state": {"times": 20}}],
},
'agents': {
'agent_class': 'CounterModel',
'topology': 'default',
'fixed': [{'state': {'times': 10}}, {'state': {'times': 20}}],
}
}
},
}
s = simulation.from_config(config)
env = s.get_env()
assert isinstance(env.agents[0], agents.CounterModel)
assert env.agents[0].G == env.topologies['default']
assert env.agents[0]['times'] == 10
assert env.agents[0]['times'] == 10
assert env.agents[0].G == env.G
assert env.agents[0]["times"] == 10
assert env.agents[0]["times"] == 10
env.step()
assert env.agents[0]['times'] == 11
assert env.agents[1]['times'] == 21
assert env.agents[0]["times"] == 11
assert env.agents[1]["times"] == 21
def test_init_and_count_agents(self):
"""Agents should be properly initialized and counting should filter them properly"""
#TODO: separate this test into two or more test cases
# TODO: separate this test into two or more test cases
config = {
'max_time': 10,
'model_params': {
'agents': [{'agent_class': CustomAgent, 'weight': 1, 'topology': 'default'},
{'agent_class': CustomAgent, 'weight': 3, 'topology': 'default'},
"max_time": 10,
"model_params": {
"agents": [
{"agent_class": CustomAgent, "weight": 1, "topology": True},
{"agent_class": CustomAgent, "weight": 3, "topology": True},
],
'topologies': {
'default': {
'path': join(ROOT, 'test.gexf')
}
},
"topology": {"path": join(ROOT, "test.gexf")},
},
}
s = simulation.from_config(config)
@@ -120,40 +108,45 @@ class TestMain(TestCase):
assert env.count_agents(weight=3) == 1
assert env.count_agents(agent_class=CustomAgent) == 2
def test_torvalds_example(self):
"""A complete example from a documentation should work."""
config = serialization.load_file(join(EXAMPLES, 'torvalds.yml'))[0]
config['model_params']['network_params']['path'] = join(EXAMPLES,
config['model_params']['network_params']['path'])
config = serialization.load_file(join(EXAMPLES, "torvalds.yml"))[0]
config["model_params"]["network_params"]["path"] = join(
EXAMPLES, config["model_params"]["network_params"]["path"]
)
s = simulation.from_config(config)
env = s.run_simulation(dry_run=True)[0]
for a in env.network_agents:
skill_level = a.state['skill_level']
if a.id == 'Torvalds':
assert skill_level == 'God'
assert a.state['total'] == 3
assert a.state['neighbors'] == 2
elif a.id == 'balkian':
assert skill_level == 'developer'
assert a.state['total'] == 3
assert a.state['neighbors'] == 1
skill_level = a.state["skill_level"]
if a.id == "Torvalds":
assert skill_level == "God"
assert a.state["total"] == 3
assert a.state["neighbors"] == 2
elif a.id == "balkian":
assert skill_level == "developer"
assert a.state["total"] == 3
assert a.state["neighbors"] == 1
else:
assert skill_level == 'beginner'
assert a.state['total'] == 3
assert a.state['neighbors'] == 1
assert skill_level == "beginner"
assert a.state["total"] == 3
assert a.state["neighbors"] == 1
def test_serialize_class(self):
ser, name = serialization.serialize(agents.BaseAgent, known_modules=[])
assert name == 'soil.agents.BaseAgent'
assert name == "soil.agents.BaseAgent"
assert ser == agents.BaseAgent
ser, name = serialization.serialize(agents.BaseAgent, known_modules=['soil', ])
assert name == 'BaseAgent'
ser, name = serialization.serialize(
agents.BaseAgent,
known_modules=[
"soil",
],
)
assert name == "BaseAgent"
assert ser == agents.BaseAgent
ser, name = serialization.serialize(CustomAgent)
assert name == 'test_main.CustomAgent'
assert name == "test_main.CustomAgent"
assert ser == CustomAgent
pickle.dumps(ser)
@@ -166,72 +159,63 @@ class TestMain(TestCase):
assert i == des
def test_serialize_agent_class(self):
'''A class from soil.agents should be serialized without the module part'''
"""A class from soil.agents should be serialized without the module part"""
ser = agents.serialize_type(CustomAgent)
assert ser == 'test_main.CustomAgent'
assert ser == "test_main.CustomAgent"
ser = agents.serialize_type(agents.BaseAgent)
assert ser == 'BaseAgent'
assert ser == "BaseAgent"
pickle.dumps(ser)
def test_deserialize_agent_distribution(self):
agent_distro = [
{
'agent_class': 'CounterModel',
'weight': 1
},
{
'agent_class': 'test_main.CustomAgent',
'weight': 2
},
{"agent_class": "CounterModel", "weight": 1},
{"agent_class": "test_main.CustomAgent", "weight": 2},
]
converted = agents.deserialize_definition(agent_distro)
assert converted[0]['agent_class'] == agents.CounterModel
assert converted[1]['agent_class'] == CustomAgent
assert converted[0]["agent_class"] == agents.CounterModel
assert converted[1]["agent_class"] == CustomAgent
pickle.dumps(converted)
def test_serialize_agent_distribution(self):
agent_distro = [
{
'agent_class': agents.CounterModel,
'weight': 1
},
{
'agent_class': CustomAgent,
'weight': 2
},
{"agent_class": agents.CounterModel, "weight": 1},
{"agent_class": CustomAgent, "weight": 2},
]
converted = agents.serialize_definition(agent_distro)
assert converted[0]['agent_class'] == 'CounterModel'
assert converted[1]['agent_class'] == 'test_main.CustomAgent'
assert converted[0]["agent_class"] == "CounterModel"
assert converted[1]["agent_class"] == "test_main.CustomAgent"
pickle.dumps(converted)
def test_templates(self):
'''Loading a template should result in several configs'''
configs = serialization.load_file(join(EXAMPLES, 'template.yml'))
"""Loading a template should result in several configs"""
configs = serialization.load_file(join(EXAMPLES, "template.yml"))
assert len(configs) > 0
def test_until(self):
config = {
'name': 'until_sim',
'model_params': {
'network_params': {},
'agents': {
'fixed': [{
'agent_class': agents.BaseAgent,
}]
"name": "until_sim",
"model_params": {
"network_params": {},
"agents": {
"fixed": [
{
"agent_class": agents.BaseAgent,
}
]
},
},
'max_time': 2,
'num_trials': 50,
"max_time": 2,
"num_trials": 50,
}
s = simulation.from_config(config)
runs = list(s.run_simulation(dry_run=True))
over = list(x.now for x in runs if x.now > 2)
assert len(runs) == config['num_trials']
assert len(runs) == config["num_trials"]
assert len(over) == 0
def test_fsm(self):
'''Basic state change'''
"""Basic state change"""
class ToggleAgent(agents.FSM):
@agents.default_state
@agents.state
@@ -250,7 +234,8 @@ class TestMain(TestCase):
assert a.state_id == a.ping.id
def test_fsm_when(self):
'''Basic state change'''
"""Basic state change"""
class ToggleAgent(agents.FSM):
@agents.default_state
@agents.state

View File

@@ -1,4 +1,4 @@
'''
"""
Mesa-SOIL integration tests
We have to test that:
@@ -8,13 +8,15 @@ We have to test that:
- Mesa visualizations work with SOIL simulations
'''
"""
from mesa import Agent, Model
from mesa.time import RandomActivation
from mesa.space import MultiGrid
class MoneyAgent(Agent):
""" An agent with fixed initial wealth."""
"""An agent with fixed initial wealth."""
def __init__(self, unique_id, model):
super().__init__(unique_id, model)
self.wealth = 1
@@ -33,15 +35,15 @@ class MoneyAgent(Agent):
def move(self):
possible_steps = self.model.grid.get_neighborhood(
self.pos,
moore=True,
include_center=False)
self.pos, moore=True, include_center=False
)
new_position = self.random.choice(possible_steps)
self.model.grid.move_agent(self, new_position)
class MoneyModel(Model):
"""A model with some number of agents."""
def __init__(self, N, width, height):
self.num_agents = N
self.grid = MultiGrid(width, height, True)
@@ -58,7 +60,7 @@ class MoneyModel(Model):
self.grid.place_agent(a, (x, y))
def step(self):
'''Advance the model by one step.'''
"""Advance the model by one step."""
self.schedule.step()

View File

@@ -10,7 +10,7 @@ from soil import config, network, environment, agents, simulation
from test_main import CustomAgent
ROOT = os.path.abspath(os.path.dirname(__file__))
EXAMPLES = join(ROOT, '..', 'examples')
EXAMPLES = join(ROOT, "..", "examples")
class TestNetwork(TestCase):
@@ -19,21 +19,13 @@ class TestNetwork(TestCase):
Load a graph from file if the extension is known.
Raise an exception otherwise.
"""
config = {
'network_params': {
'path': join(ROOT, 'test.gexf')
}
}
G = network.from_config(config['network_params'])
config = {"network_params": {"path": join(ROOT, "test.gexf")}}
G = network.from_config(config["network_params"])
assert G
assert len(G) == 2
with self.assertRaises(AttributeError):
config = {
'network_params': {
'path': join(ROOT, 'unknown.extension')
}
}
G = network.from_config(config['network_params'])
config = {"network_params": {"path": join(ROOT, "unknown.extension")}}
G = network.from_config(config["network_params"])
print(G)
def test_generate_barabasi(self):
@@ -41,88 +33,73 @@ class TestNetwork(TestCase):
If no path is given, a generator and network parameters
should be used to generate a network
"""
cfg = {
'params': {
'generator': 'barabasi_albert_graph'
}
}
cfg = {"params": {"generator": "barabasi_albert_graph"}}
with self.assertRaises(Exception):
G = network.from_config(cfg)
cfg['params']['n'] = 100
cfg['params']['m'] = 10
cfg["params"]["n"] = 100
cfg["params"]["m"] = 10
G = network.from_config(cfg)
assert len(G) == 100
def test_save_geometric(self):
"""
There is a bug in networkx that prevents it from creating a GEXF file
There is a bug in networkx that prevents it from creating a GEXF file
from geometric models. We should work around it.
"""
G = nx.random_geometric_graph(20, 0.1)
env = environment.NetworkEnvironment(topology=G)
f = io.BytesIO()
assert env.topologies['default']
network.dump_gexf(env.topologies['default'], f)
assert env.G
network.dump_gexf(env.G, f)
def test_networkenvironment_creation(self):
"""Networkenvironment should accept netconfig as parameters"""
model_params = {
'topologies': {
'default': {
'path': join(ROOT, 'test.gexf')
}
"topology": {"path": join(ROOT, "test.gexf")},
"agents": {
"topology": True,
"distribution": [
{
"agent_class": CustomAgent,
}
],
},
'agents': {
'topology': 'default',
'distribution': [{
'agent_class': CustomAgent,
}]
}
}
env = environment.Environment(**model_params)
assert env.topologies
assert env.G
env.step()
assert len(env.topologies['default']) == 2
assert len(env.G) == 2
assert len(env.agents) == 2
assert env.agents[1].count_agents(state_id='normal') == 2
assert env.agents[1].count_agents(state_id='normal', limit_neighbors=True) == 1
assert env.agents[1].count_agents(state_id="normal") == 2
assert env.agents[1].count_agents(state_id="normal", limit_neighbors=True) == 1
assert env.agents[0].neighbors == 1
def test_custom_agent_neighbors(self):
"""Allow for search of neighbors with a certain state_id"""
config = {
'model_params': {
'topologies': {
'default': {
'path': join(ROOT, 'test.gexf')
}
},
'agents': {
'topology': 'default',
'distribution': [
{
'weight': 1,
'agent_class': CustomAgent
}
]
}
"model_params": {
"topology": {"path": join(ROOT, "test.gexf")},
"agents": {
"topology": True,
"distribution": [{"weight": 1, "agent_class": CustomAgent}],
},
},
'max_time': 10,
"max_time": 10,
}
s = simulation.from_config(config)
env = s.run_simulation(dry_run=True)[0]
assert env.agents[1].count_agents(state_id='normal') == 2
assert env.agents[1].count_agents(state_id='normal', limit_neighbors=True) == 1
assert env.agents[1].count_agents(state_id="normal") == 2
assert env.agents[1].count_agents(state_id="normal", limit_neighbors=True) == 1
assert env.agents[0].neighbors == 1
def test_subgraph(self):
'''An agent should be able to subgraph the global topology'''
"""An agent should be able to subgraph the global topology"""
G = nx.Graph()
G.add_node(3)
G.add_edge(1, 2)
distro = agents.calculate_distribution(agent_class=agents.NetworkAgent)
aconfig = config.AgentConfig(distribution=distro, topology='default')
env = environment.Environment(name='Test', topologies={'default': G}, agents=aconfig)
aconfig = config.AgentConfig(distribution=distro, topology=True)
env = environment.Environment(name="Test", topology=G, agents=aconfig)
lst = list(env.network_agents)
a2 = env.find_one(node_id=2)