Agent
Agent or Holon ?
Janus was designed to easily convert a non-composed agent (classical view of agent concept) to a composed one, called holon.
An agent in Janus may be designed using the traditional agent-based approach or using an organizational perspective based on the CRIO metamodel.
If you wants to create a composed agent, Janus provides a default implementation of holon using the organizational perspective. A composed agent is considered as a agent composed of a set of groups where other agents may play roles and interact. The communication between a composed agent and its member is managed by a specific organization, called HolonicOrganization. More details on this aspect may be found in the following reference paper : An Organizational Platform For Holonic And Multiagent Systems.
In Janus, the terms of Agent or Holon are used in an indistinct manner, because every agent can be composed. By atomic agent, we refer to a non-composed agent.
Agent's basic structure and lifecycle
Each agent in Janus is implemented as first-class entity using a dedicated java class. The lifecycle of an agent is decomposed in three fundamental activities, each one managed by a specific method:
- Activate : it corresponds to the initilization phase of the agent. The activate method is automatically called by the Janus kernel when an agent is launch.
Usually, this method is the right moment to request the first set of roles played by the considered agent. - Live : it corresponds to the main part of the agent's lifecycle. The live method will be called in the behavior of the agent playing this role.
Each call to this method should run one step of the role behavior.
Caution: if you use infinite loop in live method of an agent, especially if this agent is launch as a light (non threaded) agent. A such practice may block the execution of your agent. The agent scheduler will enter in the live method and never exit. Janus natively provides a collections of tools to manage the scheduling of agents and agent's roles. So use it :-) - End : It is the termination activity. All the resources used by the agent may be free in the end method. Janus already provides a default implementations of this methods that aims at freeing the various roles played by the agent.
This life-cycle is common with the agent class in Janus, it is defined by the Activable Interface.
??? illustrates the standard agent's life-cycle. Agent starts unborn until there activate() function is invoked and terminated. During the alive state, the function live() is continuously invoked by the kernel. This loop is breaking down when the agent is killed (by invoking killMe() or kill()). Then the agent reaches the died state and run its end().
??? illustrates the finer agent's life-cyle, which is currently implemented in the AgentLifeState enumeration. The main difference between the standard life-cycle and the finer life-cycle is that additional states are introduced for transitions:
- born:
activate()is under running; - dying:
killMe()orkill()was invoked but agent's destruction is not yet proceeded; - breaking_down:
end()is under running.
The code below, describes the typical architecture of an agent in Janus.
// A simple annotation used to specify the datatype of the parameters // required for the initialization of the agent. // These parameters corresponds to the one provided by the class that // has launch this agent using the launchLightAgent or launchHeavyAgent methods. // These parameters are automatically passed to the <em>activate</em> methods // i.e. fixedParameters={Integer.class} @AgentActivationPrototype( fixedParameters={} ) public class MyAgent extends Agent { public MyAgent() { } @Override public Status activate(Object... parameters) { //Initializes capacities and memory //Creates or joins groups and requests roles //... return StatusFactory.ok(this); } /** * {@inheritDoc} */ @Override public Status live() { // In the default implementation of the live method, // Janus uses an activator to schedule the various agent's // But you may also override this method to implement // other kinds of role scheduling or simply implements //agent with adopting an organizational perspective (an agent without role) Status status = super.live(); // Do something return status; } }
Launching an Agent
In Janus, two kinds of are available:
- Heavy Agent : each heavy agent has its own thread to manage its execution. An heavy agent is thus fully autonomous in terms of computational resources
- Light Agent : a light agent shares its thread with other agents. So the access to the shared resources is managed by a scheduler which is an heavy agent. Janus provides a default scheduler for managing the execution of light agents. This latter corresponds to the Janus kernel holon. However, the developper may also develop its own scheduler.
The only difference between these two kinds of agent is the way to launch them.
Please find a below a typical java code that describes how to use launch an agent in heavy or light mode.
public class MyMASApplicationLauncher { public static void main(String[] args) throws InterruptedException { Kernel kernel = Kernels.get(false); MyAgent mylightagent = new MyAgent(); // non-threaded kernel.launchLightAgent(mylightagent, "My Light Agent Name"); MyAgent myheavyagent = new MyAgent(); // threaded kernel.launchHeavyAgent(myheavyagent, "My Heavy Agent Name"); // Kill all kernel agents and related agents. Kernels.killAll(); } }
Agent-to-Agent direct Communication
How to send message to other agents
An agent may communicate with other agents without using its roles. It may directly send a message to other agents knowing their addresses.
- One-to-One Communication
If an agent just wants to send a message to another specific agent, use this method:AgentAddress sendMessage(Message message, AgentAddress... agents)
This methods sends the specified message to one of the agents having the specified addresses if it exists.
The receiver agents is randomly selected within the specified set of agents. - One-to-Many Communication
If an agent wants to inform a set of agents, use this method:This method broadcasts the specified message to all agents having the specified addresses.void broadcastMessage(Message message, AgentAddress... agents)
Communication in Organizational Context (Agent as RolePlayer)
In Janus, various communication mechanism are available for an agent. An agent may use the previously described agent-to-agent direct communication but it can also use an organizational communication approach based on role and group concepts. An agent can thus send a message to another agent if these two agents share a common group and play a role in this group. In this case, agent use its role to communicate.
- One-to-One Communication
If an agent just wants to send a message to another specific agent within the same group, use this method:void sendMessage(GroupAddress group, Class<? extends Role> senderRole, Class<? extends Role> receiverRole, AgentAddress receiverAddress, Message message)
This methods sends the specified message to one agent playing the specified role and having the specified address if it exists.
If an agent wants to send a message to a specific agent playing a given role without knowing its address. An agent playing the specified receiverRole in the group will be randomly selected:
This methods sends the specified message to a randomly chosen agent playing the specified role. The address of the chosen receiver is returned by the function.AgentAddress sendMessage(GroupAddress group, Class<? extends Role> senderRole, Class<? extends Role> receiverRole, Message message)
- One-to-Many Communication
If a role wants to inform all agents playing a specific role in its group, use this method:This method broadcasts the specified message to all agents playing the specified role.void broadcastMessage(GroupAddress group, Class<? extends Role> senderRole, Class<? extends Role> receiverRole, Message message)
Another way to send message from agent context using role consist in getting one of the role currently played by the agent, and use its public methods to send/broadcast messages. The java code provided below describes this approach:
// Get the instance of MyRole1 class Role r = this.getRole(MyRole1.class); // Use this role as interface to send a message to MyRole2 r.broadcastMessage(MyRole2.class, new MyMessage()); //or r.sendMessage(MyRole2.class, new MyMessage());
How to manage message reception
In Janus, each agent and each role is associated to a personal mailbox. This agent's mailbox is composed by the collection of the mailboxes of the roles which is currently playing and one specific mailbox to manage agent-to-agent direct communication.
If you want to access to the mailbox of an agent, just call getMailbox() method from the agent context to get the mailbox and process messages using dedicated methods. But a mailbox also implements iterable on message, so you may also directly use this method to process all waiting messages. Please find below a typical java code to process messages of an agent (idem for a role):
for(Message msg : getMailbox()) { if (msg instanceof SomeMessageClass1) { //do something } else if (msg instanceof SomeMessageClass2) { //do something } else { //do something } }
Several additional functions permits to quickly access to the mail boxes:
-
getMessage(): consume the first message in the mail box; -
peekMessage(): get but do not consume the first message in the mail box; -
getMessages(): reply all the messages in the mail box as an iterator; -
peekMessages(): reply but do not consume all the messages in the mail box as an iterator; -
hasMessage(): indicate if a message is currently sotred in the mail box.
Agent Memory: how to easily exchange information between an agent and its roles
In various applications, it is often required to adapt the behavior of a role according to dynamic characteristics of its player agent. It is also useful to model a kinds of memory storing data that can be modified by various roles of the same agent at the same time. The concept of agent memory was introduced to solve such issues. It considered as a data container embedded inside the agent. This memory is private to the agent context, it may be modified by the agent itself or its roles. It may thus be considered as a way to exchange information between roles played by an agent. This concept of memory is implemented in a fully generic way in Janus. The developper may define its own implementation. However, Janus already provides two basics implementations of memory that are briefly described below :
- BlackBoardMemory : This is the default implementation of memory. It is a simple blackboard that can modified by the agent and its various roles, ie. each data on the black board is identified by a key.
This implementation doesn't manage concurrent access. - JavaReflectionMemory : Implementation of an agent memory using a direct access to the getter and setter methods of the agent class.
Please find a below a typical java code that describes how to use the concept of memory to enable the communication between a agent and one of its role.
public class MyAgent extends Agent { //..... public MyAgent() { Memory memory = getMemory(); assert(memory!=null); memory.putMemorizedData(MyRole.WORLD_HEIGHT, 50); memory.putMemorizedData(MyRole.WORLD_WIDTH, 40); } public Status activate(Object... parameters) { GroupAddress group = getOrCreateGroup(organization(MyOrganization.class)); requestRole(MyRole.class, group, RoleInitData); return StatusFactory.ok(this); } //..... } public class MyRole extends Role { //..... public static final String WORLD_HEIGHT = "WORLD_HEIGHT"; public static final String WORLD_WIDTH = "WORLD_WIDTH"; public Status activate(Object... parameters) { Memory memory = getMemory(); this.width = memory.getMemorizedData(WORLD_WIDTH, Integer.class); this.height = memory.getMemorizedData(WORLD_HEIGHT, Integer.class); return StatusFactory.ok(this); } //..... public Status live() { Memory memory = getMemory(); Map<AgentAddress,WorldState> locations = (Map<AgentAddress,WorldState>)memory.getMemorizedData(POSITIONS); memory.putMemorizedData(IS_PREY_CATCHED, Boolean.TRUE); return StatusFactory.ok(this); } }




