Overview

The goal of Creamas is to aid in development, research and teaching of agent-based systems which exhibit creative behaviour. Creamas is built on top of aiomas, from which the basic agent and container (Environment in Creamas) are subclassed. The container provides a communication route (RPC) between agents. If you need to know more about how the low level communication works, see aiomas documentation.

Agents And Environments

Agents (CreativeAgent) in Creamas focus on building artifacts and evaluating them. Each agent belongs to Environment, which serves as a communication route between the agents. Environment can also hold other information shared by the agents or, e.g., provide means for the agents to communicate only with nearby agents in a 2D-grid. Agents are created by handling the environment as the first initialization parameter.

from creamas.core import CreativeAgent, Environment
# Create environment to tcp://localhost:5555/
env = Environment.create(('localhost', 5555))
# Create agent with address tcp://localhost:5555/0
a1 = CreativeAgent(env)
# Create agent with address tcp://localhost:5555/1
a2 = CreativeAgent(env)

The fundamental design principle guiding the development of Creamas is that agents create artifacts (Artifact) in some domain(s) and evaluate them. Most of the functionality is geared towards this goal.

However, Creamas does not take a stand on the design of the multi-agent systems or individual agents and is quite agnostic considering the agent implementations. Therefore, Creamas can be used to develop arbitrary agent societies, but you might want to take a look at aiomas if you do not need any of the additional functionality provided by Creamas.

Communication Between the Agents

Communication between the agents in one of the key interests in multi-agent systems. In Creamas, agents can expose their own functions as services to other agents by using expose() decorator (originating from aiomas library). An agent wishing to communicate with another agent connects to the remote agent and calls the exposed function remotely. To this end they have to know the other agent’s (tcp) address.

Note

Agents derived from CreativeAgent are supposed to store addresses of other agents in their connections.

Consider a following simple multiply() service an agent AgentA has:

import creamas

class AgentA(creamas.CreativeAgent):

    @creamas.expose
    async def multiply(self, int1, int2):
        return int1 * int2

Now, another agent, AgentB, knowing that AgentA’s address is addr can then use AgentA’s multiply service by connecting to AgentA through its environment.

import random
import creamas

class AgentB(creamas.CreativeAgent):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.int1 = random.randint(0, 100)
        self.int2 = random.randint(0, 100)

    async def complex_computation(self, addr):
        remote_agent_A = await self.env.connect(addr)
        value = await remote_agent_A.multiply(self.int1, self.int2)
        # do something with the value
        return value

Importantly, the agents do not have to reside in the same environment or even on the same machine, i.e. you can connect to any agent or environment as long as you know the address of the specific agent in the environment. However, the remote agent and its environment have to be implemented using classes derived from aiomas library, like Creamas agent classes and environments do.

Note

Connecting to an agent and calling an exposed function are done asynchronously using await keyword before the function call. Any method using await has to have async keyword at the start of its function definition.

Creating and Analyzing Agent Connections

Studying varying social network structures in creative agent systems is one of the main purposes Creamas exists. To generate agent connections and to analyze them, Creamas has some built-in support for integration with NetworkX graph library. These functionalities are found from creamas.nx module. The main functions are connections_from_graph() and graph_from_connections(). They allow priming agent-to-agent connections with varying properties and analyzing them easily using NetworkX graph structures.

Evaluating Artifacts

Exchanging artifacts, and information about them, is an eminent functionality for agents in Creamas. An agent can ask other agent’s opinions about its own artifacts or other artifacts it has seen. This allows the agent to accumulate knowledge about the artifact preferences of other agents, which may alter the agent’s own behavior.

Method ask_opinion() offers a shortcut to ask an opinion about an artifact from a remote agent.

# This is a toy example. Code won't work off the shelf as the agents 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
remote_addr = a1.connections[0]
ret = a1.ask_opinion(remote_addr, ar)
# get a1's current attitude towards a2
att = a1.get_attitude(remote_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)

Iterative Simulation

Creamas provides an easy to use Simulation which can be used to run iterative simulations using agents’ act(). Simulations can be created directly or they can be given an environment at initialization time. See Using Simulation for details.

Voting and Other Social Choice Functions

Creamas offers some basic social choice/social decision making behavior for agents in the form of voting. Agents can publish their own artifacts as candidates. These candidates can then be collected and voted upon. Optionally, agents can validate each others candidates, i.e. exercise veto power on them, before voting takes place. See Voting 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), and distributing the environments on several nodes is in ds-module (see Distributed Systems).

If you want to learn more about multiprocessing and distributed system support in Creamas, read an overview of them: Multiprocessing and Distributed Systems.