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:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
|
||||
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user