Creamas - Creative Multi-Agent Systems¶

Creamas project is created as a tool for researching creative multi-agent systems. Project’s main repository is in github.
Overview¶
Creamas is developed as a tool for people to effortlessly build, and do research on, multi-agent systems in the field of computational creativity. Creamas is built on top of aiomas, which provides a communication route (RPC) between agents and the basic agent and container (environment) implementations.
Agents And Environments¶
Agents in Creamas focus on building artifacts and evaluating them. Each agent belongs to an environment, which also serves as a communication route between agents. Environment can also hold other information shared by all agents, or, e.g. provide means for the agents to communicate with nearby agents in a 3D-space. Agents are created by giving the environment as an initialization parameter.
from creamas.core import CreativeAgent, Environment
# Create environment to http://localhost:5555/
env = Environment.create(('localhost', 5555))
# Create agent with address http://localhost:5555/0
a1 = CreativeAgent(env)
# Create agent with address http://localhost:5555/1
a2 = CreativeAgent(env)
The fundamental design principle guiding the development of Creamas is that each agent creates artifacts in some domain(s) and evaluates them. A lot of the current functionality is geared towards this goal. However, Creamas does not take a stand on the design of the multi-agent systems and is therefore quite agnostic of the actual agent implementations.
Exchanging artifacts and information about them is one of the main tasks of the agents. An agent can also ask other agent’s opinions about their own artifacts or other artifacts they have seen. This allows the agent to accumulate knowledge about the preferences of other agents, which may alter the agent’s own activity.
# This is a toy example. Code won't work off the shelf as the agent's don't
# have any evaluation methods, which we will see in the next section.
from creamas.core import Artifact
# Create some artifact.
ar = Artifact()
# first evaluate it yourself
ev = a1.evaluate(ar)
# ask other agent's opinion (evaluation) of it
ret = a1.ask_opinion(a2.addr, ar)
# get a1's current attitude towards a2
att = a1.get_attitude(a2.addr)
# get difference between evaluations
diff = abs(ev - ret)
# if evaluations are very similar, become friendlier with the agent
if diff < 0.2:
a1.set_attitude(a2.addr, att + 0.1)
# if evaluations are very different, dislike the agent
if diff > 0.8
a1.set_attitude(a2.addr, att - 0.1)
Features, Mappers And Rules¶
Warning
Functionality in this section is not yet fully developed and tested.
Agents can evaluate artifacts by extracting features from them. As features can have all kinds of outputs, they are paired with mappers. A mapper serves as a function from feature’s outputs to the interval \([-1, 1] \in \mathbb{R}\). Where features are though to be artifact domain depended, and shareable between agents, mappers represent individual agent’s preferences over possible feature values.
Rules combine a set of features, and their corresponding mappers, to a functional unit. Rules also have weight for each feature, which may inhibit its effect on the overall rule’s evaluation. In its most basic form rule has one feature and its mapper, but agents are encouraged to merge existing rules together, or add new features to them in order to make them more expressive.
Simulation¶
Creamas provides an easy to use simulation creator which can be used to execute
agents act()
to run the environment in an iterative manner. See
Using Simulation for details.
Support for Multiple Cores and Distributed Systems¶
Creamas has inherent support for using multiple cores on a single machine and
distributing your environments on multiple nodes, e.g., on a computing cluster.
However, these functionalities are not yet fully tested, but have been used in
several systems and platforms effectively. Multiprocessing functionality is in
mp
-module (see Multiprocessing functionality), and distributing the environments on several
nodes is in ds
-module (see Distributed Systems).
Installation¶
Creamas is developed with Python 3.5,
the easiest way to install the latest distribution of Creamas is using pip
:
pip install creamas
We encourage the use of virtual environments to avoid conflicting package requirements in your projects.
Installing the development version¶
If you want to use the latest development version, you can clone the repository from git:
$>git clone https://github.com/assamite/creamas.git creamas
$>cd creamas
$>pyvenv-3.5 venv # create venv for python 3.5
$>source venv/bin/activate # start virtualenv
$>pip install -r requirements.txt
$>pip install -r c_reqs.txt # packages using C are in different file for readthedocs
Implementing Agent Classes¶
All agents used in creamas must inherit from
CreativeAgent
. They should also accept one
parameter that is passed down to super().__init__()
:
- environment:
Environment
where the agent lives
Each agent class should call super().__init__()
first thing in
__init__()
, for example:
from creamas.core.agent import CreativeAgent
class MyAgent(CreativeAgent):
def __init__(self, environment, *args, **kwargs):
super().__init__(environment)
# Your own initialization code
Using Simulation¶
creamas contains easy to use iterative simulation to perform experiments on single computer set up. Each agent wishing to use simulation has to implement act:
-
CreativeAgent.
act
(*args, **kwargs)[source] Trigger agent to act. Dummy method, override in subclass.
This function serves as the main function for the simulations, and is called for each agent on each iteration step of the simulation.
Raises: NotImplementedError – If not overridden in subclass.
Simulation calls act for each agent in each simulation step. What agents do in their turn is up to you!
Simple Simulations¶
Creating simple iterative simulation is made easy with
create
. Observe.
from mymodule import MyAgent
from creamas.core.simulation import Simulation
agent_kwargs = {'foo': 'bar', 'Cthulhu': 'rises'}
# Create initial simulation with default parameters using MyAgents-class
# and passing agent_kwargs to each agent at initialization time.
sim = Simulation.create(agent_cls = MyAgent, agent_kwargs=agent_kwargs, n_agents=20)
# Advance simulation by single step
sim.step()
# End simulation and destroy it's environment.
sim.end()
create offers few arguments to modify simulation initialization:
- You can create simulation with multiple agent classes each with its own keyword arguments and number of agents.
from mymodule import MyAgent, CthulhuAgent
from.creamas.core.simulation import Simulation
myagent_kwargs = {'foo': 'bar', 'Cthulhu': 'rises'}
cthulhu_kwargs = {"R'lyeh": 'sunken'}
agent_kwargs=[myagent_kwargs,cthulhu_kwargs]
agent_cls = [MyAgent, CthulhuAgent]
n_agents = [10, 1]
sim = Simulation.create(agent_cls=agent_cls, n_agents=n_agents,agent_kwargs=agent_kwargs)
- You can create simulation with your own environment, which is automatically passed down to the agents at their initialization time.
from mymodule import StarSpawnAgent
from myenv import InnsmouthEnvironment
from creamas.core.simulation import Simulation
env_kwargs = {'weather': 'drizzle, slight wind', 'atmosphere': 'gloomy'}
sim = Simulation.create(agent_cls=StarSpawnAgent,env_cls=InnsmouthEnvironment,env_kwargs=env_kwargs)
Complex Simulation Setups¶
If you need more control on creating the environment and agents, you can
create your environment directly and then create your agents. After you have
fully initialized the environment, you can then pass it to the
Simulation
at initialization time.
from mymodule import StarSpawnAgent
from creamas.core.enviroment import Environment
from creamas.core.simulation import Simulation
env = Environment()
for i in range(10):
# do some complex calculation
# ...
Starspawn(env, cause_havoc=True, non_euclidian_angle=mystery)
sim = Simulation(env=env)
Advancing Simulation¶
Simulation holds few different ways to advance it.
# Advance simulation by single step (executing all agents once)
sim.step()
# Advance simulation by executing single agent.
sim.next()
# Advance simulation to the end of the current step.
sim.finish_step()
# Advance simulation by 10 steps
sim.steps(10)
Logging Simulation¶
TODO: Log the logging of logger.
API Documentation¶
Core¶
Agent¶
Agent module holds CreativeAgent implementation, a subclass of
aiomas.Agent
, which holds basic functionality thought to be shared by all
creative agents.
-
class
creamas.core.agent.
CreativeAgent
(environment, resources=0, name=None, log_folder=None, log_level=10)[source]¶ Base class for all creative agents.
All agents share certain common attributes:
Variables: - env – The environment where the agent lives.
- max_res (int) – Agent’s resources per step, 0 if agent has unlimited resources.
- cur_res (int) – Agent’s current resources.
- R (list) – rules agent uses to evaluate artifacts
- W (list) – Weight for each rule in R, in [-1,1].
- A (list) – Artifacts the agent has created so far
- D (dict) – Domain knowledge, other agents’ artifacts seen by this agent
- connections (list) – Other agents this agent knows
- attitudes (list) – Attitude towards each agent in connections, in [-1,1]
- name (str) – Name of the agent. Defaults to address of the agent.
- age – Age of the agent
-
coroutine
act
(*args, **kwargs)[source]¶ Trigger agent to act. Dummy method, override in subclass.
This function serves as the main function for the simulations, and is called for each agent on each iteration step of the simulation.
Raises: NotImplementedError – If not overridden in subclass.
-
add_artifact
(artifact)[source]¶ Add artifact to A.
Raises: TypeError – If the artifact is not a member of Artifact
or its subclass.
-
add_connection
(addr, attitude=0.0)[source]¶ Added agent with given address to current connections with given initial attitude.
Does nothing if agent is already in connections.
Parameters: - addr (str) – Address of the agent to be added
- attitude (float) – initial attitude towards agent, in [-1, 1]
Returns: True if the agent was successfully added, False otherwise.
-
add_rule
(rule, weight)[source]¶ Add rule to R with initial weight.
Parameters: - rule (~creamas.core.rule.Rule) – rule to be added
- weight (float) – initial weight for the rule
Raises: TypeError – if rule is not subclass of
Rule
Returns: true if rule was successfully added, otherwise false
Rtype bool:
-
coroutine
ask_opinion
(addr, artifact)[source]¶ Ask agent’s opinion about artifact.
The artifact object should be serializable by the environment.
Parameters: - addr (str) – Address of the agent which opinion is asked
- artifact (object) – artifact to be evaluated
Returns: agent’s evaluation of the artifact
Return type: float
-
close
(folder=None)[source]¶ Perform any bookkeeping needed before closing the agent.
Dummy implementation, override in subclass if needed.
Parameters: folder (str) – Folder where the agent should save its data.
-
coroutine
connect
(addr)[source]¶ Connect to agent in given address using the agent’s environment.
This is a shortcut to
agent.env.connect(addr)
.Returns: Proxy
object for the connected agent.
-
evaluate
(artifact)[source]¶ Evaluate artifact with agent’s current rules and weights.
Parameters: artifact ( Artifact
) – artifact to be evaluatedReturns: agent’s evaluation of the artifact, in [-1,1], and framing. In this basic implementation framing is always None. Return type: tuple Actual evaluation formula is:
\[e(A) = \frac{\sum_{i=1}^{n} r_{i}(A)w_i} {\sum_{i=1}^{n} \lvert w_i \rvert},\]where \(r_{i}(A)\) is the \(i\) th rule’s evaluation on artifact \(A\), and \(w_i\) is the weight for rule \(r_i\).
-
get_attitude
(addr)[source]¶ Get attitude towards agent in connections. If agent is not in connections, returns None.
-
publish
(artifact)[source]¶ Publish artifact to agent’s environment.
Parameters: artifact ( Artifact
) – artifact to be published
-
coroutine
random_connection
()[source]¶ Connect to random agent from current connections.
Returns: Proxy
object for the connected agent.
-
remove_rule
(rule)[source]¶ Remove rule from R and its corresponding weight from W.
Parameters: rule (~creamas.core.rule.Rule) – rule to remove Raises: TypeError – if rule is not subclass of Rule
Returns: true if rule was successfully removed, otherwise false Rtype bool:
-
set_attitude
(addr, attitude)[source]¶ Set attitude towards agent. If agent is not in connections, adds it.
-
validate
(candidates)[source]¶ Validate a list of candidate artifacts.
Candidate validation should prune unwanted artifacts from the overall candidate set. Agent can use its own reasoning to validate the given candidates. The method should return a subset of the given candidates list containing the validated artifacts (i.e. the artifacts that are not pruned).
This basic implementation returns the given candidate list as is.
-
vote
(candidates)[source]¶ Rank artifact candidates.
The voting is needed for the agents living in societies using social social decision making. The function should return a sorted list of (candidate, evaluation)-tuples. Depending on the social choice function used, the evaluation might be omitted from the actual decision making, or only a number of (the highest ranking) candidates may be used.
This basic implementation ranks candidates based on
evaluate()
.Parameters: candidates – list of Artifact
objects to be rankedReturns: Ordered list of (candidate, evaluation)-tuples
-
A
¶ Artifacts created so far by the agent.
-
D
¶ Domain knowledge accumulated by this agent.
Dictionary of agents and their artifacts.
-
R
¶ Rules agent uses to evaluate artifacts. Each rule in R is expected to be a callable with single parameter, the artifact to be evaluated. Callable should return a float in [-1,1]; where 1 means that rule is very prominent in the artifact; 0 means that there is none of that rule in the artifact; -1 means that the artifact shows traits opposite to the rule.
-
W
¶ Weights for the features. Each weight should be in [-1,1].
-
age
¶ Age of the agent.
-
attitudes
¶ Attitudes towards agents in connections.
-
connections
¶ Addresses of the other agents the agent is aware of.
-
cur_res
¶ Agent’s current resources. Capped to maximum resources.
-
env
¶ The environment where the agent lives. Must be a subclass of
Environment
.
-
max_res
¶ Maximum resources for the agent per act. If 0, agent has unlimited resources. If maximum resources are set below current resources, current resources are capped to new maximum resources.
-
name
¶ Human readable name of the agent. The agent should not change its name during its lifetime.
Artifact¶
Artifact module holds Artifact, a base class for artifacts created by creative agents.
-
class
creamas.core.artifact.
Artifact
(creator, obj, domain=<class 'int'>)[source]¶ Base class for artifacts.
-
add_eval
(agent, e, fr=None)[source]¶ Add or change agent’s evaluation of the artifact with given framing information.
Parameters: - agent – agent which did the evaluation
- e (float) – evaluation for the artifact
- fr (object) – framing information for the evaluation
-
domain
()[source]¶ Domain of the artifact. Domain must match feature’s possible domains at evaluation time, or None is returned.
-
creator
¶ CreativeAgent
who created the artifact.
-
evals
¶ dict - evaluations of the artifact.
-
framings
¶ dict - framings given for the evaluations.
-
obj
¶ Artifact itself.
-
Feature¶
Feature module holds base implementation for features
(Feature
) that creative agents have in their
rulesets.
-
class
creamas.core.feature.
Feature
(name, domains, rtype)[source]¶ Base feature class that is callable after initialization.
Each feature value takes as an input an artifact, and returns feature’s value for that artifact. If artifact type is not supported, feature’s evaluation should return None.
Returned feature values can be of any type, but rules (
Rule
) should have appropriate mappers to map possible feature’s values to the interval [-1, 1].Usage example:
from myfeat import MyFeature from myartifact import MyArtifact myart = MyArtifact(*myparams) myart.rtype == mytype # True f = MyFeature() ret = f(myart) type(ret) == mytype # True
Parameters: - name (str) – feature’s name
- domains (list) – all artifact domains (
type
) that can be evaluated with the feature. - rtype – value type returned by this feature
-
extract
(artifact)[source]¶ Extract feature from artifact. Dummy implementation, override in subclass.
Returns: feature value extracted from the artifact Return type: rtype Raises: NotImplementedError – if not overridden in subclass
-
domains
¶ Set of acceptable artifact domains for this feature. Other types of artifacts will return None when tried to extract with this feature.
-
name
¶ Name of the feature.
-
rtype
¶ Value type returned by this feature.
Rule¶
Rule module holds base implementation of rule
(Rule
). Rules combine features and mappers to
functional body, where each feature also has weight attached to it.
TODO: write rule to accept other rules in F also.
-
class
creamas.core.rule.
Rule
(rules, weights, evaluation='ave')[source]¶ Rule is a treelike data structure consisting of other Rules and RuleLeaf instances. Rules are used by agents to evaluate artifacts.
Like features, rules offer a simple interface where artifact can be evaluated by calling a rule instance with artifact as the only argument. Rules should return a float in [-1, 1] when evaluated.
from creamas.core.rule import Rule rule = Rule([myleaf, myleaf2, myrule], [1.0, 1.0, 1.0]) res = rule(myartifact)
Parameters: - rules (list) – Subrules for this rule. Subrule can be either an iterable of length 2, the (Feature, Mapper)-pair, or another Rule instance.
- weights (list) – Weights for the subrules.
- evaluation –
How rule’s internal evaluation is done. Either one of the predefined functions, or user defined callable which takes two arguments: rule and artifact (in that order). Predefined functions and their keywords are:
- ‘ave’:
weighted_average()
- ‘min’:
minimum()
- ‘max’:
maximum()
- ‘ave’:
-
add_subrule
(subrule, weight)[source]¶ Add subrule to the rule.
Parameters: - subrule – Subrule to add to this rule. Subrule can be either an iterable of length 2, the (Feature, Mapper)-pair, or another Rule instance.
- weight (float) – weight of the subrule
Returns: false if subrule already in rule, true otherwise
Return type: bool
-
R
¶ list - subrules in this rule.
-
W
¶ list - weights for subrules in this rule.
-
domains
¶ Rule’s acceptable artifact domains is the union of all its subrules acceptable domains. Each artifact is evaluated only with subrules that do not return None when the feature is evaluated with it.
Mapper¶
Mapper module hold base implementation for mappers. Mappers are functions, that map each feature’s possible values to the interval [-1, 1]. While features are though to belong to artifacts of certain types, mappers usually belong to single agent making it possible for each agent to have their own appreciation standards for the feautre.
Environment¶
This module holds Enviroment
-class, an universe where the agents live.
Environment holds methods for inter-agent communication and some utilities that
are usually needed when implementing creative multi-agent systems.
All implementations should subclass Environment
in order to provide basic
functionality for the system to operate.
Environments are used by defining their address at the instantation time, and adding agents to their container.
-
class
creamas.core.environment.
Environment
(base_url, clock, connect_kwargs)[source]¶ Base environment class inherited from
aiomas.Container
.-
add_artifact
(artifact)[source]¶ Add artifact with given framing to the environment.
Parameters: artifact (object) – Artifact to be added.
-
add_artifacts
(artifacts)[source]¶ Add artifacts to artifacts.
Parameters: artifacts – list of Artifact
objects
-
create_initial_connections
(n=5)[source]¶ Create random initial connections for all agents.
Parameters: n (int) – the number of connections for each agent
-
destroy
(folder=None, as_coro=False)[source]¶ Destroy the environment.
Does the following:
- calls
save_info()
- for each agent: calls
close()
- Shuts down its RPC-service.
- calls
-
get_agents
(address=True, agent_cls=None)[source]¶ Get agents in the environment.
Parameters: - address (bool) – If true, returns only addresses of the agents.
- agent_cls – Optional, if specified returns only agents belonging to that particular class.
-
coroutine
get_artifacts
(agent=None)[source]¶ Get artifacts published by certain agent.
Returns: All artifacts published by the agent. Return type: list
-
get_random_agent
(agent)[source]¶ Return random agent that is not the same as agent given as parameter.
Parameters: agent ( CreativeAgent
) – Agent that is not wanted to returnReturns: random, non-connected, agent from the environment Return type: CreativeAgent
-
is_ready
()[source]¶ Check if the environment is fully initialized.
The function is mainly used by the multiprocessing environment managers and distributed environments to ensure that the environment has been correctly initialized before any other preparations are done for the environments or the simulation is started.
Override the function in the subclasses which need more time consuming initialization routines. The function should return True when the environment is ready be used in a simulation, or when any cross-environment initialization routines can be run. That is, the environment is inherently in a coherent state, and can execute orders from managers or simulations.
Return type: bool Returns: This basic implementation returns always True.
-
perform_voting
(method='IRV', accepted=1)[source]¶ Perform voting to decide the ordering of the current candidates.
Voting calls each agent’s
vote()
-method, which might be costly in larger societies.Parameters: - method (str) – Used voting method. One of the following: IRV = instant run-off voting, mean = best mean vote (requires cardinal ordering for votes), best = best singular vote (requires cardinal ordering, returns only one candidate), least_worst = least worst singular vote, random = selects random candidates
- accepted (int) – the number of returned candidates
Returns: list of
Artifact
objects, accepted artifacts. Some voting methods, e.g. mean, also return the associated scores for each accepted artifact.Rype: list
-
save_info
(folder, *args, **kwargs)[source]¶ Save information accumulated during the environments lifetime.
Called from
destroy()
. Override in subclass.Parameters: folder (str) – root folder to save information
-
coroutine
trigger_act
(addr=None, agent=None)[source]¶ Trigger agent to act.
If agent is None, then looks the agent by the address.
Raises: ValueError – if both agent and addr are None.
-
validate_candidates
()[source]¶ Validate current candidates in the environment by pruning candidates that are not validated at least by one agent, i.e. they are vetoed.
In larger societies this method might be costly, as it calls each agents’
validate()
.
-
age
¶ Age of the environment.
-
artifacts
¶ Published artifacts for all agents.
-
candidates
¶ Current artifact candidates, subject to e.g. agents voting to determine which candidate(s) are added to artifacts.
-
log_folder
¶ Logging folder for the environment. If set, will create py:class::creamas.logging.ObjectLogger for that folder.
-
logger
¶ Logger for the environment.
-
name
¶ Name of the environment.
-
Simulation¶
Basic simulation implementation where agents in the same environment can be run in an iterative manner.
-
class
creamas.core.simulation.
Simulation
(env, callback=None, log_folder=None)[source]¶ Base class for iterative simulations.
In each step the simulation calls
act()
for each agent in simulation environment.Create simulation for previously set up environment.
Parameters: - env (
Environment
orMultiEnvironment
) – fully initialized environment with agents already set - callback (callable) – function to call after each simulation step
Parat str log_folder: folder to log simulation information
-
classmethod
create
(agent_cls=None, n_agents=10, agent_kwargs={}, env_cls=<class 'creamas.core.environment.Environment'>, env_kwargs={}, callback=None, conns=0, log_folder=None)[source]¶ Convenience function to create simple simulations.
Method first creates environment, then instantiates agents into it with give arguments, and finally creates simulation for the environment.
Parameters: - agent_cls – class for agents, or list of classes. If list, then n_agents and agent_kwargs are expected to be lists also.
- n_agents – amount of agents for simulation, or list of amounts
- agent_kwargs – keyword arguments passed to agents at creation time, or list of keyword arguments.
- env_cls (
Environment
) – environment class for simulation - env_kwargs (dict) – keyword arguments passed to environment at creation time
- callback (callable) – optional callable to call after each simulation step
- conns – Create conns amount of initial (random) connections for agents in the simulation environment.
- log_folder (str) – folder for possible logging. This overwrites log_folder keyword argument from agent_kwargs and env_kwargs.
-
step
()[source]¶ Progress simulation with a single step.
Can not be called when some of the agents have not acted for the current step.
-
steps
(n)[source]¶ Progress simulation with given amount of steps.
Can not be called when some of the agents have not acted for the current step.
Parameters: n (int) – amount of steps to run
-
age
¶ Age of the simulation.
-
callback
¶ Callable to be called after each simulation step for any extra bookkeeping, etc.. Should accept one parameter: age that is current simulation age.
-
env
¶ Environment for the simulation. Must be a subclass of
Environment
.
-
name
¶ Name of the simulation.
-
order
¶ Order in which agents are run.
Possible values:
- alphabetical: agents are sorted by name
- random: agents are shuffled
Changing the order while iteration is unfinished will take place in the next iteration.
- env (
Core package holds base implementations for agents, environments, simulations, features and artifacts.
- core.agent - base agent implementation
- core.artifact - base artifact implementation
- core.feature - base feature implementation
- core.rule - base feature implementation
- core.mapper - base mapper implementation
- core.environment - base environment, each agent lives in an environment
- core.simulation - base simulation to run environment’s agents in iterations
Agents¶
Agents module holds various agent implementations inheriting from
CreativeAgent
.
Multiprocessing functionality¶
This module contains multiprocessing implementation for
Environment
,
MultiEnvironment
.
A MultiEnvironment
holds several
Environment
slaves, which are spawned on
their own processes, and uses managers to obtain much of the same functionality
as the single processor environment. See EnvManager
and
MultiEnvManager
for details.
Warning
This functionality is currently largely untested. However, it seems to
work as intended and may be used in
Simulation
.
-
class
creamas.mp.
EnvManager
(container)[source]¶ A manager for
Environment
.Managers are used in environments which need to be able to execute commands originating from outside sources, e.g. in slave environments inside a multiprocessing environment.
A manager can spawn other agents into its environment, and can execute other tasks relevant to the environment. The manager should always be the first agent created to the environment.
Note
You should not need to create managers directly, instead pass the desired manager class to an instance of
MultiEnvironment
at its initialization time.-
clear_candidates
()[source]¶ Clear candidates in the managed environment.
This is a managing function for
clear_candidates()
.
-
get_agents
(address=True, agent_cls=None)[source]¶ Get agents from the managed environment
This is a managing function for the
get_agents()
, but returned agent lists exclude this manager by default.
-
coroutine
get_artifacts
()[source]¶ Get all artifacts from the host environment.
Returns: All the artifacts in the environment.
-
coroutine
get_older
(addr=None)[source]¶ Make agent in addr to get older, i.e. advance its internal clock.
-
coroutine
is_ready
()[source]¶ Check if the managed environment is ready.
This is a managing function for
is_ready()
.
-
set_host_addr
(addr)[source]¶ Set host (or master) manager for this manager.
Parameters: addr – Address for the host manager.
-
coroutine
spawn_n
(agent_cls, n, *args, **kwargs)[source]¶ Spawn n agents to the managed environment. This is a convenience function so that one does not have to repeatedly make connections to the environment to spawn multiple agents with the same parameters.
See
spawn()
for details.
-
stop
(folder=None)[source]¶ Stop the managed environment, close all the agents and set stop_received on this agent to True.
-
coroutine
trigger_all
()[source]¶ Trigger all agents in the managed environment to act once.
This is a managing function for
trigger_all()
.
-
-
class
creamas.mp.
MultiEnvManager
(container)[source]¶ A manager for
MultiEnvironment
.A Manager can spawn other agents into its slave environments, and can execute other tasks relevant to the whole environment. The manager should always be the first (and usually only) agent created for the multi-environment’s managing environment. The actual simulation agents should be created to the slave environments, typically using multi-environment’s or its manager’s functionality.
Note
You should not need to create managers directly, instead pass the desired manager class to an instance of
MultiEnvironment
at its initialization time.-
coroutine
destroy
()[source]¶ A managing function for
trigger_all()
.
-
coroutine
get_agents
(address=True, agent_cls=None)[source]¶ Get all agents in all the slave environments.
This is a managing function for
creamas.mp.MultiEnvironment.get_agents()
.
-
coroutine
get_candidates
(addr)[source]¶ Get candidates from the environment manager in addr manages.
-
coroutine
get_older
(addr)[source]¶ Make agent in addr to get older, i.e. advance its internal clock.
-
coroutine
get_slave_agents
(addr, address=True, agent_cls=None)[source]¶ Get agents in the specified manager’s environment.
Parameters: - addr (str) – Address of the environment’s manager
- address (bool) – Return only the addresses of the agents, not proxies.
- agent_cls – If specified, return only the agents that are members of the class.
See also
creamas.environment.Environment.get_agents()
creamas.mp.EnvManager.get_agents()
,creamas.mp.MultiEnvironment.get_agents()
-
coroutine
is_ready
()[source]¶ A managing function for
is_ready()
.
-
coroutine
kill
(addr, folder=None)[source]¶ Send stop command to the manager agent in a given address. This will shutdown the manager’s environment.
-
coroutine
set_host_manager
(addr)[source]¶ Set this manager as a host manager to the manager in addr.
-
coroutine
spawn
(addr, agent_cls, *agent_args, **agent_kwargs)[source]¶ Spawn an agent to an environment in a manager in the given address.
agent_args and agent_kwargs are passed to the manager doing to spawning to be used as the agent’s initialization parameters.
Parameters: - addr (str) – Environment’s manager’s address
- agent_cls – Class of the agent as a string, e.g. creamas.grid:GridAgent
Returns: Proxy
and port of the spawned agent
-
coroutine
spawn_n
(addr, agent_cls, n, *agent_args, **agent_kwargs)[source]¶ Same as
spawn()
, but spawn multiple agents with same initialization parameters.This should considerably reduce the time needed to spawn a large number of homogeneous agents.
agent_args and agent_kwargs are passed to the manager doing to spawning to be used as the agent’s initialization parameters.
Parameters: - addr (str) – Environment’s manager’s address
- agent_cls – Class of the agent as a string, e.g. creamas.grid:GridAgent
- n (int) – Number of agents to spawn.
Returns: List of (
Proxy
, port) tuples for the spawned agents.... seealso:
:meth:`creamas.mp.EnvManager.spawn_n`
-
coroutine
trigger_all
()[source]¶ Trigger all agents in the managed multi-environment to act.
This is a managing function for
trigger_all()
.
-
coroutine
-
class
creamas.mp.
MultiEnvironment
(addr, env_cls=None, mgr_cls=None, slave_addrs=[], slave_env_cls=None, slave_params=None, slave_mgr_cls=None, name=None, clock=None, extra_ser=None, log_folder=None, log_level=20)[source]¶ Environment for utilizing multiple processes (and cores) on a single machine.
MultiEnvironment
has a managing environment, typically containing only a single manager, and a set of slave environments each having their own manager and (once spawned) the actual agents.Currently, the implementation assumes that the slave environments do not use any time consuming internal initialization. If the slaves are not reachable after a few seconds after the initialization, an exception is raised. Thus, any slave environments should do their additional preparations, e.g. agent spawning, outside their
__init__()
, afterMultiEnvironment
has been initialized successfully.Note
MultiEnvironment
and the slave environments are internally initialized to haveaiomas.MsgPack
as the codec for the message serialization. Any communication to these environments and agents in them must use the same codec.Parameters: - addr – (HOST, PORT) address for the manager environment.
- env_cls – Class for the environment. Must be a subclass of
Environment
. - mgr_cls – Class for the multi-environment’s manager.
- addrs – List of (HOST, PORT) addresses for the slave-environments.
- slave_env_cls – Class for the slave environments.
- slave_params – If not None, must be a list of the same size as addrs. Each item in the list containing parameter values for one slave environment.
- slave_mgr_cls – Class of the slave environment managers.
- name (str) – Name of the environment. Will be shown in logs.
-
add_artifact
(artifact)[source]¶ Add artifact with given framing to the environment.
Parameters: artifact (object) – Artifact to be added.
-
add_artifacts
(artifacts)[source]¶ Add artifacts to artifacts.
Parameters: artifacts – list of Artifact
objects
-
check_ready
()[source]¶ Check if this multi-environment itself is ready.
Override in subclass if it needs any additional (asynchronous) initialization other than spawning its slave environments.
Return type: bool Returns: This basic implementation returns always True.
-
coroutine
create_connection
(addr, addr2)[source]¶ Create connection from agent in addr to agent in addr2.
This does not create a connection the other way around.
-
create_initial_connections
(n=5)[source]¶ Create random initial connections for all agents.
Parameters: n (int) – the number of connections for each agent
-
destroy
(folder=None, as_coro=False)[source]¶ Destroy the multiprocessing environment and its slave environments.
-
get_agents
(address=True, agent_cls=None)[source]¶ Get agents from the slave environments. This method excludes each slave environment’s manager agent from the returned list.
Essentially calls
get_agents()
for each of the slave environment managers.Parameters: - address (bool) – If True, returns only addresses of the agents, otherwise returns
a
Proxy
object for each agent. - agent_cls – If specified, returns only agents that are members of that particular class.
Returns: List of
Proxy
objects or addresses as specified by the input parameters.- address (bool) – If True, returns only addresses of the agents, otherwise returns
a
-
get_artifacts
(agent)[source]¶ Get artifacts published by certain agent.
Returns: All artifacts published by the agent. Return type: list
-
get_random_agent
(agent)[source]¶ Return random agent that is not the same as agent given as parameter.
Parameters: agent ( CreativeAgent
) – Agent that is not wanted to returnReturns: random, non-connected, agent from the environment Return type: CreativeAgent
-
coroutine
get_votes
(addr, candidates)[source]¶ Get votes for candidates from a manager in addr.
Manager should implement
get_votes()
.See also
creamas.mp.EnvManager.get_votes()
-
coroutine
is_ready
()[source]¶ Check if the multi-environment has been fully initialized.
This calls each slave environment managers’
is_ready()
and checks if the multi-environment itself is ready by callingcheck_ready()
.
-
perform_voting
(method='IRV', accepted=1)[source]¶ Perform voting to decide the ordering of the current candidates.
Voting calls each agent’s
vote
-method, which might be costly in larger societies.Parameters: - method (str) – Used voting method. One of the following: IRV = instant run-off voting, mean = best mean vote (requires cardinal ordering for votes), best = best singular vote (requires cardinal ordering, returns only one candidate), least_worst = least worst singular vote, random = selects random candidates
- accepted (int) – the number of returned candidates
Returns: list of :py:class`~creamas.core.artifact.Artifact`s, accepted artifacts
Rype: list
-
save_info
(folder, *args, **kwargs)[source]¶ Save information accumulated during the environments lifetime.
Called from
destroy()
. Override in subclass.Parameters: folder (str) – root folder to save information
-
coroutine
spawn
(agent_cls, *args, addr=None, **kwargs)[source]¶ Spawn a new agent.
If addr is None, spawns the agent in the slave environment with currently smallest number of agents.
Parameters: - agent_cls – Subclass of
CreativeAgent
- addr – Address for the slave enviroment’s manager, if specified.
Returns: Proxy and address for the created agent.
- agent_cls – Subclass of
-
coroutine
trigger_act
(addr)[source]¶ Trigger agent in addr to act.
This method is very inefficient if used repeatedly for a large number of agents.
-
coroutine
trigger_all
()[source]¶ Trigger all agents in all the slave environments to act asynchronously.
-
validate_candidates
()[source]¶ Validate current candidates in the environment by pruning candidates that are not validated at least by one agent, i.e. they are vetoed.
In larger societies this method might be costly, as it calls each agents’
validate_candidates
-method.
-
addrs
¶ Addresses of the slave environment managers.
-
age
¶ Age of the environment.
-
artifacts
¶ Published artifacts for all get_agents.
-
candidates
¶ Current artifact candidates, subject to e.g. agents voting to determine which candidate(s) are added to artifacts.
-
env
¶ Environment hosting the manager of this multi-environment. This environment is also used without the manager to connect to the slave environment managers.
-
manager
¶ This multi-environment’s manager.
-
name
¶ Name of the environment.
-
creamas.mp.
spawn_container
(addr=('localhost', 5555), env_cls=<class 'creamas.core.environment.Environment'>, mgr_cls=<class 'creamas.mp.EnvManager'>, set_seed=True, *args, **kwargs)[source]¶ Spawn a new environment in a given address as a coroutine.
Arguments and keyword arguments are passed down to the created environment at initialization time.
If setproctitle is installed, this function renames the title of the process to start with ‘creamas’ so that the process is easily identifiable, e.g. with
ps -x | grep creamas
.
-
creamas.mp.
spawn_containers
(addrs=[('localhost', 5555)], env_cls=<class 'creamas.core.environment.Environment'>, env_params=None, mgr_cls=<class 'creamas.mp.EnvManager'>, *args, **kwargs)[source]¶ Spawn environments in a multiprocessing
multiprocessing.Pool
.Arguments and keyword arguments are passed down to the created environments at initialization time if env_params is None. If env_params is not None, then it is assumed to contain individual initialization parameters for each environment in addrs.
Parameters: - addrs – List of (HOST, PORT) addresses for the environments.
- env_cls – Callable for the environments. Must be a subclass of
Environment
. - env_params (Iterable of same length as addrs or None.) – Initialization parameters for the environments.
- mgr_cls – Callable for the managers. Must be a subclass of
EnvManager
.s
Returns: The created process pool and the ApplyAsync results for the spawned environments.
-
coroutine
creamas.mp.
start
(addr, env_cls=<class 'creamas.core.environment.Environment'>, mgr_cls=<class 'creamas.mp.EnvManager'>, *env_args, **env_kwargs)[source]¶ Coroutine that starts an environment with
mgr_cls
manager agent.The agent will connect to addr
('host', port)
and wait for commands to spawn new agents within its environment.The env_args and env_kwargs will be passed to
env_cls.create()
factory function.This coroutine finishes after manager’s
stop()
was called or when aKeyboardInterrupt
is raised.Parameters: - addr – (HOST, PORT) for the new environment
- env_cls – Class of the environment, subclass of
Environment
. - mgr_cls – Class of the manager agent, subclass of
EnvManager
.
Distributed Systems¶
The module holds a base implementation, DistributedEnvironment
,
for simulations and environments where the resources span over multiple nodes
on computing clusters or other distributed systems.
Note
The module needs asyncssh (>=1.6.2, developed with 1.6.2) to function. Asyncssh is not installed by default as a dependency.
-
class
creamas.ds.
DistributedEnvironment
(host, port, nodes, logger=None)[source]¶ Distributed environment which manages several nodes containing multi-environments.
This environment is used to spawn the multi-environments on the different servers (nodes) using SSH-connections. The spawning process assumes that the user can make a SSH-connection without login credentials to each node. The environment can then be used to wait until all the nodes are ready (have done their individual initialization) and do optional additional preparing of the nodes (e.g. adding inter-node connections between agents).
After all the nodes are ready and prepared, the environment can be used to run an iterative (asynchronous) simulation using
DistributedEnvironment.trigger_all()
which callstrigger_all()
for each node’s manager.Warning
To free the resources on each node, it is crucial to call
DistributedEnvironment.destroy()
after the simulation has been done. Otherwise, some rogue processes are likely to be left unattended on the external nodes.The intended order of usage is as follows:
ds = DistributedEnvironment(*args, **kwargs) # 'pool' holds the process pool for SSH-connections to nodes, # 'r' contains the (future) return values of the connections. pool, r = ds.spawn_nodes(spawn_cmd) timeout = 30 loop = asyncio.get_event_loop() nodes_ready = loop.run_until_complete(ds.wait_nodes(timeout)) if nodes_ready: # All nodes are ready so we can do additional preparation loop.run_until_complete(ds.prepare_nodes()) # Run the simulation for i in range(10): loop.run_until_complete(ds.trigger_all()) # Destroy the simulation afterwards to free the resources on each node. ds.destroy()
Parameters: - host – Host of the env property (this node). The host should not be present in nodes.
- port – Port for the managing environments on each node (incl. this node), e.g. 5555. This port is not checked for availability before the node environments are spawned.
- nodes – List of nodes (servers) which are used to host the multi-environments. Each node should allow SSH-connections without login credentials.
- logger – Optional logger for this simulation.
-
destroy
()[source]¶ Destroy the simulation.
Stop the nodes and free other resources associated with the simulation.
-
coroutine
prepare_nodes
(*args, **kwargs)[source]¶ Prepare nodes (and slave environments and agents) so that they are ready for the simulation. Should be called after
wait_nodes()
.Note
Override in the subclass for the intended functionality.
-
spawn_nodes
(spawn_cmd)[source]¶ Spawn all multi-environments on the nodes using SSH.
Parameters: spawn_cmd (int) – str or list, command(s) used to spawn the environment on each node. If list, it must contain one command for each node in nodes, if str the same command is used for each node. Warning
The spawning process of the nodes assumes that the manager agent of each multi-environment (on each node) is initialized in the port given by the parameter port at the distributed environment’s initialization time.
-
coroutine
stop_nodes
(timeout=1)[source]¶ Stop all the nodes by sending a stop-message to their managers.
Parameters: timeout (int) – Timeout for connecting to each manager. If a connection can not be made before the timeout expires, the resulting error for that particular manager is logged, but the stopping of other managers is not halted.
-
coroutine
trigger_all
()[source]¶ Trigger all agents in all the nodes to act asynchronously.
This method makes a connection to each manager in manager_addrs and asynchronously executes
trigger_all()
in all of them.
-
coroutine
wait_nodes
(timeout)[source]¶ Wait until all nodes are ready or timeout expires. Should be called after
spawn_nodes()
.Node is assumed ready when its managers
is_ready()
-method returns True.Parameters: timeout (int) – Timeout (in seconds) after which the method will return even though all the nodes are not ready yet.
-
env
¶ Environment used to communicate with node managers.
The environment does not hold any agents by default, but it is easy to create a manager for it on your own, if the node managers need to be able to communicate back to this environment.
-
manager_addrs
¶ Addresses of node managers.
These addresses are derived from nodes and port parameters given at the initialization time, and are used to communicate tasks (trigger agents) to the nodes. Each manager is assumed to be the first agent in its own managed environment.
-
nodes
¶ Environment nodes (excluding the current host).
Altering the nodes after the initialization most probably causes unexpected behavior.
-
coroutine
creamas.ds.
ssh_exec
(server, cmd)[source]¶ Execute a command on a given server using asynchronous SSH-connection.
The method does not propagate exceptions raised during the SSH-connection, instead, the exceptions are caught and returned. The method will exit after the first exception is raised.
Parameters: - server (str) – Address of the server
- cmd (str) – Command to be executed
Returns: (closed SSH-connection, exception)-tuple, if no exceptions are caught, the second value is None.
Features¶
Various implemented features
Mappers¶
Various mapper implementations. Mappers are functions that map possible feature value’s to the interval [-1, 1]. In Creamas, they are used by individual agent’s to represent agent’s preferences over features values.
-
class
creamas.mappers.
BooleanMapper
(mode='10')[source]¶ Boolean mapper that has four different modes.
Depending on the mode, True and False are mapped either to 1, 0, or -1.
mode True False ‘10’ 1.0 0.0 ‘01’ 0.0 1.0 ‘1-1’ 1.0 -1.0 ‘-11’ -1.0 1.0 -
mode
¶ Mode of the mapper.
-
-
class
creamas.mappers.
LinearMapper
(lo, hi, mode='01')[source]¶ Mapper that maps values in given interval linearly.
Can be used for features that return either ‘int’ or ‘float’ values.
Based on its mode, maps lo and hi to different end points and values between them to a straight line. Depending on the mode, lo and hi have following end points:
mode lo hi ‘10’ 1.0 0.0 ‘01’ 0.0 1.0 ‘1-1’ 1.0 -1.0 ‘-11’ -1.0 1.0 -
mode
¶ Mode of the mapper.
-
value_set
¶ Accepted value types, i.e. this mapper can be used for the features that return these types of values.
-
-
class
creamas.mappers.
DoubleLinearMapper
(lo, mid, hi, mode='01')[source]¶ Mapper that concatenates two linear mappers.
Can be used for features that return either ‘int’ or ‘float’ values.
First line is created from lo to mid and second line from mid to hi. Depending on the mode, lo, mid and hi are mapped to following end points.
mode lo mid hi ‘10’ 1.0 0.0 1.0 ‘01’ 0.0 1.0 0.0 ‘1-1’ 1.0 -1.0 1.0 ‘-11’ -1.0 1.0 -1.0 -
mode
¶ Mode of the mapper.
-
value_set
¶ Accepted value types, i.e. this mapper can be used for the features that return these types of values.
-
-
class
creamas.mappers.
GaussianMapper
(mean, std, mode='01')[source]¶ Gaussian distribution mapper.
The mapped value is relative to given Gaussian distribution’s maximum point (pmax, evaluated at point loc) and the probability density function’s value at given evaluation point (pval).
The actual value calculation changes with the mode of the mapper:
mode mapped value ‘10’ \(1.0 - (pval / pmax)\) ‘01’ \(pval / pmax\) ‘1-1’ \(1.0 - 2(pval / pmax)\) ‘-11’ \(-1.0 + 2(pval / pmax)\) Parameters: - mean (float) – mean of the mapping distribution
- std (float) – standard deviation of the mapping distribution
- mode – mode of the mapper: ‘10’, ‘01’, ‘1-1’ or ‘-11’.
-
mode
¶ Mode of the mapper.
-
class
creamas.mappers.
LogisticMapper
(x0, k, mode='01')[source]¶ Logistic function mapper.
The mapped value is relative to the logistic function’s value in the mapping point. Depending on the mode, some transformations (mirroring, shifting), might be applied to the mapped value.
Parameters: - x0 (float) – sigmoid’s midpoint
- k (float) – steepness of the curve
- mode – mode of the mapper: ‘10’, ‘01’, ‘1-1’ or ‘-11’.
-
mode
¶ Mode of the mapper.
Math¶
Various mathematical utility functions.
-
creamas.math.
gaus_pdf
(x, mean, std)[source]¶ Gaussian distribution’s probability density function.
See, e.g. Wikipedia.
Parameters: - x (float or numpy.ndarray) – point in x-axis
- mean (float) – mean or expectation
- str (float) – standard deviation
Returns: pdf(s) in point x
Return type: float or numpy.ndarray
-
creamas.math.
logistic
(x, x0, k, L)[source]¶ Logistic function.
See, e.g Wikipedia.
Parameters: - x (float or numpy.ndarray) – point in x-axis
- x0 (float) – sigmoid’s midpoint
- k (float) – steepness of the curve
- L (float) – maximum value of the curve
Returns: function’s value(s) in point x
Return type: float or numpy.ndarray
Logging¶
Logging module holds utilities that help with logging and analyzing the creative system’s behavior.
-
class
creamas.logging.
ObjectLogger
(obj, folder, add_name=False, init=True, log_level=10)[source]¶ Base logger for objects. Not a subclass of base logger.
Generates one file for each attribute to be logged.
Create new logger instance for obj in folder. If add_name is True, creates subfolder carrying
obj.name
to folder. If init is true, sets logger’s level to log_level and adds basic StreamHandler to the logger.-
log_attr
(level, attr_name)[source]¶ Log attribute to file and pass the message to underlying logger.
Parameters: - level (int) – logging level
- attr_name (str) – attribute’s name to be logged
-
write
(attr_name, prefix='age')[source]¶ Write attribute’s value to file.
Parameters: - attr_name (str) – attribute’s name to be logged
- prefix (str) – attribute’s name that is prefixed to logging message, defaults to age.
Returns: message written to file
Return type: str
-
folder
¶ Root logging folder for this logger.
-
obj
¶ Object this logger belongs to. Object has to have name attribute.
-
-
creamas.logging.
log_before
(attr, level=10)[source]¶ Decorator to log attribute’s value(s) before function call.
Implementation allows usage only for methods belonging to class. The class instance needs to have logger attribute that is subclass of
ObjectLogger
.Parameters: - level (int) – logging level
- attr (str) – name of the class instance’s parameter to be logged
-
creamas.logging.
log_after
(attr, level=10)[source]¶ Decorator to log attribute’s value(s) after function call.
Implementation allows usage only for methods belonging to class. The class instance needs to have logger variable set.
Parameters: - level (int) – logging level
- attr (str) – name of the class instance’s parameter to be logged