import palaestrai
If the above line works without error, at least the import is done. Thats a first good starter. Now let's import the rest…
import os
import pprint
import tempfile
from pathlib import Path
Setting the Runtime Configuration¶
Usually, this is not necessary like this. But because we're running a self-contained test, we want to have a new, fresh database where we want to put it. Which is, in a temporary directory.
store_dir = tempfile.TemporaryDirectory()
store_dir
<TemporaryDirectory '/tmp/tmprt0xlybf'>
We're now going to change palaestrAI's runtime configuration to point to the new directory.
from palaestrai.core import RuntimeConfig
runtime_config = RuntimeConfig()
runtime_config.reset()
runtime_config.load(
{"store_uri": "sqlite:///%s/palaestrai.db" % store_dir.name}
)
pprint.pprint(runtime_config.to_dict())
{'data_path': './_outputs', 'executor_bus_port': 4242, 'logger_port': 4243, 'logging': {'filters': {'debug_filter': {'()': 'palaestrai.core.runtime_config.DebugLogFilter'}}, 'formatters': {'debug': {'format': '%(asctime)s ' '%(name)s[%(process)d]: ' '%(levelname)s - %(message)s ' '(%(module)s.%(funcName)s in ' '%(filename)s:%(lineno)d)'}, 'simple': {'format': '%(asctime)s ' '%(name)s[%(process)d]: ' '%(levelname)s - ' '%(message)s'}}, 'handlers': {'console': {'class': 'logging.StreamHandler', 'formatter': 'simple', 'level': 'INFO', 'stream': 'ext://sys.stdout'}, 'console_debug': {'class': 'logging.StreamHandler', 'filters': ['debug_filter'], 'formatter': 'debug', 'level': 'DEBUG', 'stream': 'ext://sys.stdout'}}, 'loggers': {'palaestrai.agent': {'level': 'ERROR'}, 'palaestrai.agent.agent_conductor': {'level': 'ERROR'}, 'palaestrai.agent.brain': {'level': 'ERROR'}, 'palaestrai.agent.muscle': {'level': 'ERROR'}, 'palaestrai.core': {'level': 'ERROR'}, 'palaestrai.environment': {'level': 'ERROR'}, 'palaestrai.experiment': {'level': 'ERROR'}, 'palaestrai.simulation': {'level': 'ERROR'}, 'palaestrai.store': {'level': 'ERROR'}, 'palaestrai.types': {'level': 'ERROR'}, 'palaestrai.util': {'level': 'ERROR'}, 'palaestrai.visualization': {'level': 'ERROR'}, 'sqlalchemy.engine': {'level': 'ERROR'}}, 'root': {'handlers': ['console', 'console_debug'], 'level': 'ERROR'}, 'version': 1}, 'major_domo_client_retries': 3, 'major_domo_client_timeout': 300000, 'profile': False, 'public_bind': False, 'store_buffer_size': 20, 'store_uri': 'sqlite:////tmp/tmprt0xlybf/palaestrai.db', 'time_series_store_uri': 'influx+localhost:8086'}
Create the Database¶
Next, we create the database at the given URI. It will complain that we're not using TimescaleDB, which is okay.
from palaestrai.store.database_util import setup_database
setup_database(runtime_config.store_uri)
Could not create extension timescaledb and create hypertables: (sqlite3.OperationalError) near "EXTENSION": syntax error [SQL: CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;] (Background on this error at: https://sqlalche.me/e/14/e3q8). Your database setup might lead to noticeable slowdowns with larger experiment runs. Please upgrade to PostgreSQL with TimescaleDB for the best performance.
assert Path("%s/palaestrai.db" % store_dir.name).is_file()
Run Experiment¶
In this part, we load our dummy experiment and run it.
experiment_file_path = Path().absolute() / ".." / "fixtures" / "dummy_run.yml"
assert experiment_file_path.is_file()
rc = palaestrai.execute(str(experiment_file_path))
assert rc[1].value == 4
rc
Your palaestrAI installation has version 3.5.2 but your run file uses version 3.4, which may be incompatible.
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
(['Yo-ho, a dummy experiment run for me!'], <ExecutorState.EXITED: 4>)
If you see something like ('Yo-ho, a dummy experiment run for me!', <ExecutorState.EXITED: 4>)
as output of the previous line, then congratulations, everything went well! Now onwards to the final step…
Verify Data from the Store¶
Now that an experiment has been run, there should be something in the store. Note that we don't check whether something meaningful is in the store, only that there is something in the store.
from sqlalchemy import select
import palaestrai.store
import palaestrai.store.database_model as dbm
dbh = palaestrai.store.Session()
q = select(dbm.Experiment)
str(q)
'SELECT experiments.document, experiments.document_json, experiments.id, experiments.name \nFROM experiments'
experiment = dbh.execute(q).first()[dbm.Experiment]
experiment.name
'Dummy Experiment record for ExperimentRun Yo-ho, a dummy experiment run for me!'
our_experiment_run = experiment.experiment_runs[0]
str(our_experiment_run)
'<ExperimentRun(id=1, uid="Yo-ho, a dummy experiment run for me!", experiment_id=1, document={\'py/object\': \'palaestrai.experiment.experiment_run.ExperimentRun\', \'seed\': 42, \'rng\': {\'py/reduce\': [{\'py/function\': \'numpy.random._pickle.__randomstate_ctor\'}, {\'py/tuple\': [\'MT19937\']}, {\'bit_generator\': \'MT19937\', \'state\': {\'key\': {\'py/object\': \'numpy.ndarray\', \'values\': \'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\', \'shape\': [624], \'dtype\': \'uint32\', \'byteorder\': \'<\'}, \'pos\': 624}, \'has_gauss\': 0, \'gauss\': 0.0}]}, \'uid\': \'Yo-ho, a dummy experiment run for me!\', \'version\': \'3.4\', \'schedule_config\': [{\'phase_0\': {\'environments\': [{\'environment\': {\'name\': \'palaestrai.environment.dummy_environment:DummyEnvironment\', \'uid\': \'myenv\', \'params\': {\'discrete\': True}}}], \'agents\': [{\'name\': \'mighty_defender\', \'brain\': {\'name\': \'palaestrai.agent.dummy_brain:DummyBrain\', \'params\': {}}, \'muscle\': {\'name\': \'palaestrai.agent.dummy_muscle:DummyMuscle\', \'params\': {}}, \'objective\': {\'name\': \'palaestrai.agent.dummy_objective:DummyObjective\', \'params\': {\'params\': 1}}, \'sensors\': [\'myenv.0\', \'myenv.1\', \'myenv.2\', \'myenv.3\', \'myenv.4\'], \'actuators\': [\'myenv.0\', \'myenv.1\', \'myenv.2\', \'myenv.3\', \'myenv.4\']}, {\'name\': \'evil_attacker\', \'brain\': {\'name\': \'palaestrai.agent.dummy_brain:DummyBrain\', \'params\': {}}, \'muscle\': {\'name\': \'palaestrai.agent.dummy_muscle:DummyMuscle\', \'params\': {}}, \'objective\': {\'name\': \'palaestrai.agent.dummy_objective:DummyObjective\', \'params\': {\'params\': 1}}, \'sensors\': [\'myenv.5\', \'myenv.6\', \'myenv.7\', \'myenv.8\', \'myenv.9\'], \'actuators\': [\'myenv.5\', \'myenv.6\', \'myenv.7\', \'myenv.8\', \'myenv.9\']}], \'simulation\': {\'name\': \'palaestrai.simulation:Vanilla\', \'conditions\': [{\'name\': \'palaestrai.simulation:VanillaSimControllerTerminationCondition\', \'params\': {}}]}, \'phase_config\': {\'mode\': \'train\', \'worker\': 1, \'episodes\': 1}}}, {\'phase_1\': {\'environments\': [{\'environment\': {\'name\': \'palaestrai.environment.dummy_environment:DummyEnvironment\', \'uid\': \'myenv\', \'params\': {\'discrete\': True}}}], \'agents\': [{\'name\': \'mighty_defender\', \'load\': {\'agent\': \'mighty_defender\', \'experiment_run\': \'Yo-ho, a dummy experiment run for me!\', \'phase\': 0}, \'brain\': {\'name\': \'palaestrai.agent.dummy_brain:DummyBrain\', \'params\': {}}, \'muscle\': {\'name\': \'palaestrai.agent.dummy_muscle:DummyMuscle\', \'params\': {}}, \'objective\': {\'name\': \'palaestrai.agent.dummy_objective:DummyObjective\', \'params\': {\'params\': 1}}, \'sensors\': [\'myenv.0\', \'myenv.1\', \'myenv.2\', \'myenv.3\', \'myenv.4\'], \'actuators\': [\'myenv.0\', \'myenv.1\', \'myenv.2\', \'myenv.3\', \'myenv.4\']}, {\'name\': \'evil_attacker\', \'load\': {\'agent\': \'evil_attacker\', \'experiment_run\': \'Yo-ho, a dummy experiment run for me!\', \'phase\': 0}, \'brain\': {\'name\': \'palaestrai.agent.dummy_brain:DummyBrain\', \'params\': {}}, \'muscle\': {\'name\': \'palaestrai.agent.dummy_muscle:DummyMuscle\', \'params\': {}}, \'objective\': {\'name\': \'palaestrai.agent.dummy_objective:DummyObjective\', \'params\': {\'params\': 1}}, \'sensors\': [\'myenv.5\', \'myenv.6\', \'myenv.7\', \'myenv.8\', \'myenv.9\'], \'actuators\': [\'myenv.5\', \'myenv.6\', \'myenv.7\', \'myenv.8\', \'myenv.9\']}], \'simulation\': {\'name\': \'palaestrai.simulation:Vanilla\', \'conditions\': [{\'name\': \'palaestrai.simulation:VanillaSimControllerTerminationCondition\', \'params\': {}}]}, \'phase_config\': {\'mode\': \'train\', \'worker\': 1, \'episodes\': 1}}}], \'run_config\': {\'condition\': {\'name\': \'palaestrai.experiment:VanillaRunGovernorTerminationCondition\', \'params\': {}}}, \'_instance_uid\': \'74692c7c-ae7f-4e94-ba6a-23121db4cdf5\', \'_canonical_config\': None}>'
The document
property of the experiment run object should contain the YAML file, and we should be able to de-searialize it. Let's check that.
assert our_experiment_run.document
our_experiment_run._document_json
{'py/object': 'palaestrai.experiment.experiment_run.ExperimentRun', 'seed': 42, 'rng': {'py/reduce': [{'py/function': 'numpy.random._pickle.__randomstate_ctor'}, {'py/tuple': ['MT19937']}, {'bit_generator': 'MT19937', 'state': {'key': {'py/object': 'numpy.ndarray', 'values': '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', 'shape': [624], 'dtype': 'uint32', 'byteorder': '<'}, 'pos': 624}, 'has_gauss': 0, 'gauss': 0.0}]}, 'uid': 'Yo-ho, a dummy experiment run for me!', 'version': '3.4', 'schedule_config': [{'phase_0': {'environments': [{'environment': {'name': 'palaestrai.environment.dummy_environment:DummyEnvironment', 'uid': 'myenv', 'params': {'discrete': True}}}], 'agents': [{'name': 'mighty_defender', 'brain': {'name': 'palaestrai.agent.dummy_brain:DummyBrain', 'params': {}}, 'muscle': {'name': 'palaestrai.agent.dummy_muscle:DummyMuscle', 'params': {}}, 'objective': {'name': 'palaestrai.agent.dummy_objective:DummyObjective', 'params': {'params': 1}}, 'sensors': ['myenv.0', 'myenv.1', 'myenv.2', 'myenv.3', 'myenv.4'], 'actuators': ['myenv.0', 'myenv.1', 'myenv.2', 'myenv.3', 'myenv.4']}, {'name': 'evil_attacker', 'brain': {'name': 'palaestrai.agent.dummy_brain:DummyBrain', 'params': {}}, 'muscle': {'name': 'palaestrai.agent.dummy_muscle:DummyMuscle', 'params': {}}, 'objective': {'name': 'palaestrai.agent.dummy_objective:DummyObjective', 'params': {'params': 1}}, 'sensors': ['myenv.5', 'myenv.6', 'myenv.7', 'myenv.8', 'myenv.9'], 'actuators': ['myenv.5', 'myenv.6', 'myenv.7', 'myenv.8', 'myenv.9']}], 'simulation': {'name': 'palaestrai.simulation:Vanilla', 'conditions': [{'name': 'palaestrai.simulation:VanillaSimControllerTerminationCondition', 'params': {}}]}, 'phase_config': {'mode': 'train', 'worker': 1, 'episodes': 1}}}, {'phase_1': {'environments': [{'environment': {'name': 'palaestrai.environment.dummy_environment:DummyEnvironment', 'uid': 'myenv', 'params': {'discrete': True}}}], 'agents': [{'name': 'mighty_defender', 'load': {'agent': 'mighty_defender', 'experiment_run': 'Yo-ho, a dummy experiment run for me!', 'phase': 0}, 'brain': {'name': 'palaestrai.agent.dummy_brain:DummyBrain', 'params': {}}, 'muscle': {'name': 'palaestrai.agent.dummy_muscle:DummyMuscle', 'params': {}}, 'objective': {'name': 'palaestrai.agent.dummy_objective:DummyObjective', 'params': {'params': 1}}, 'sensors': ['myenv.0', 'myenv.1', 'myenv.2', 'myenv.3', 'myenv.4'], 'actuators': ['myenv.0', 'myenv.1', 'myenv.2', 'myenv.3', 'myenv.4']}, {'name': 'evil_attacker', 'load': {'agent': 'evil_attacker', 'experiment_run': 'Yo-ho, a dummy experiment run for me!', 'phase': 0}, 'brain': {'name': 'palaestrai.agent.dummy_brain:DummyBrain', 'params': {}}, 'muscle': {'name': 'palaestrai.agent.dummy_muscle:DummyMuscle', 'params': {}}, 'objective': {'name': 'palaestrai.agent.dummy_objective:DummyObjective', 'params': {'params': 1}}, 'sensors': ['myenv.5', 'myenv.6', 'myenv.7', 'myenv.8', 'myenv.9'], 'actuators': ['myenv.5', 'myenv.6', 'myenv.7', 'myenv.8', 'myenv.9']}], 'simulation': {'name': 'palaestrai.simulation:Vanilla', 'conditions': [{'name': 'palaestrai.simulation:VanillaSimControllerTerminationCondition', 'params': {}}]}, 'phase_config': {'mode': 'train', 'worker': 1, 'episodes': 1}}}], 'run_config': {'condition': {'name': 'palaestrai.experiment:VanillaRunGovernorTerminationCondition', 'params': {}}}, '_instance_uid': '74692c7c-ae7f-4e94-ba6a-23121db4cdf5', '_canonical_config': None}
our_experiment_run.experiment_run_instances[0].uid
'74692c7c-ae7f-4e94-ba6a-23121db4cdf5'
… and so on. For a system test, this is enough.