Chapter 3
Developing your own agents or algorithms

3.1 General considerations

In ViSiDiA, agents and algorithms can be defined using either a rewriting rule system or an Application Programming Interface (API). We here only present the creation of agents and algorithms using the ViSiDiA API.
To create a new agent or algorithm, you must create a new class in a new file. This must extend one the API classes, depending on the communication mode (synchronous or asynchronous) and the process type (fixed processes or mobile sensors). Theses API classes are located in the visidia.process.agent and visidia.process.algorithm packages, respectively. Please refer to the following table to determine which class to extend.




Asynchronous Synchronous




Fixed processes
agents Agent SynchronousAgent
algorithms Algorithm SynchronousAlgorithm




Mobile sensors
agents not implemented not implemented
algorithms not implemented SensorSyncAlgorithm





In the new class, whatever the class you extend, you have to specifiy at least two methods:

These methods will be called by ViSiDiA when loading and running your agent or algorithm, respectively.

 
To implement your algorithm or agent, you have access to several methods defined in the ViSiDiA API, depending on the API class your algorithm or agent extends. The following sections describe these methods.

3.2 Developing agents

Agents are autonomous computation entities which move on the network, using node ressources when reaching a node. Each agent has its own properties, and can acces to node whiteboards. Agents can either manage its own movement or use an agent mover which will automatize the movement.
Movement is defined by an origin vertex (node) and a destination vertex. An agent operates when it arrived at a vertex. We thus consider that an agent, if on a vertex, is always on the destination vertex.

3.2.1 Asynchronous agents

General methods

protected Collection agentsOnVertex();
Returns the collection of agents which are on each vertex.

public int getArity();
Returns the destination vertex degree.

protected int getVertexIdentity();
Returns the destination vertex identity.

protected void sleep(int milliseconds);
Pauses the agent during the given number of milliseconds.

protected int getNetSize();
Returns the net size. Provided for convenience, since an agent is not supposed to know graph global information.

Property methods

public Object getProperty(Object key);
Gets the agent property value associated to the key, or null if the key does not exist.

public Object setProperty(Object key, Object value, int status);
Adds a property to the agent. If the value is null then the property is removed. Please refer to SimulationConstants.PropertyStatus class to see available statuses.

public Object setProperty(Object key, Object value);
Adds a non-displayable property to the agent. If the value is null then the property is removed.

public Object removeProperty(Object key);
Removes the property.

public void resetProperties();
Resets properties to their initial (default) value.

public Set<Object> getPropertyKeys();
Gets all agent property keys.

public boolean containsElement(Object key);
Checks if key matches an agent property.

protected Object getVertexProperty(Object key);
Gets the destination vertex property value associated to the key, or null if the key does not exist.

protected void setVertexProperty(Object key, Object value, int status);
Adds a property to the destination vertex. Please refer to SimulationConstants.PropertyStatus class to see available statuses.

protected void setVertexProperty(Object key, Object value);
Adds a non-displayable property to the destination vertex using its previously defined status if any ; else define the property as non-displayable.

protected String getVertexLabel();
Gets the destination vertex label.

protected int getVertexIdentity();
Gets the destination vertex identity.

protected void setVertexLabel(String label);
Sets the destination vertex label.

protected void lockVertexProperties();
Locks the vertex whiteboard where the agent is. If already locked, waits until the owner unlocks it.

protected void unlockVertexProperties();
Unlocks the vertex whiteboard where the agent is.

protected boolean vertexPropertiesLocked();
Tests if destination vertex properties are locked.

protected boolean lockVertexIfPossible();
Locks the destination vertex; does nothing if it is already locked.

protected Object getEdgeProperty(int door, Object key);
Gets the property value associated to the key of the edge identified by the door number from destination vertex. Returns null if the key does not exist.

protected void setEdgeProperty(int door, Object key, Object value);
Adds a property to the edge identified by the door number from destination vertex.

Visualization methods

protected final void setDoorState(EdgeState st, int door);
Changes the door state and thus the edge color and thickness. The parameter st can be created using MarkedState or SyncState instances.

Movement methods

protected void move();
Moves the agent using its associated mover.

protected void moveBack();
Moves the agent back to the vertex from where it comes.

protected void moveToDoor(int door);
Moves agent to specific door.

protected int entryDoor();
Returns the door from which the agent comes.

protected void setAgentMover(String name);
Associates a mover to the agent. The parameter is the mover class name.

public Vertex getDestinationVertex();
Returns the agent destination vertex.

3.2.2 Synchronous agents

When creating a new synchronous agent, one method can be redefined in the new class, in addition to clone() and init() methods:

 
public int getPulse();
Gets the current pulse. This value is associated to the simulator, and thus shared by all running agents.

public void nextPulse();
The node asks for a new pulse to begin. The method waits until all agents have called this method.

3.2.3 Sensor agents

To be written.

3.3 Developing algorithms

In ViSiDiA, the same algorithm is copied to each process (each node). Each cloned algorihm is thus related to a node. When one of the following methods is called, it refers to the node to which the current algorithm copy belongs. Each node has a whiteboard, an editable set of its properties.

When creating a new algorithm, two methods can be redefined in the new class, in addition to clone() and init() methods:

3.3.1 Asynchronous algorithms

General methods

protected int getArity();
Returns the node degree.

protected int getId();
Returns the node id.

protected int getNetSize();
Returns the net size. Provided for convenience, since an algorithm is not supposed to know graph global information.

protected Enumeration<Integer> getOrientedDoors();
Gets the oriented doors of the current node. Both incoming and outgoing doors are considered.

protected boolean isIncomingDoor(int door);
Returns true if the door corresponds to an edge pointing to the current node. Also returns true if the edge is not oriented.

protected boolean isOutgoingDoor(int door);
Returns true if the door corresponds to an edge leaving the current node. Also returns true if the edge is not oriented.

Property methods

protected void putProperty(String key, Object value, int status);
Adds a property to the node. Please refer to SimulationConstants.PropertyStatus class to see available statuses.

protected void putProperty(String key, Object value);
Adds a property to the node using its previously defined status if any ; else define the property as non-displayable.

protected Object getProperty(String key);
Gets the node property value associated to the key, or null if the key does not exist.

protected Object getEdgeProperty(int door, String key);
Gets the property value associated to the key of the edge identified by the door number from current vertex, or null if the key does not exist.

protected void setEdgeProperty(int door, String key, Object value);
Adds a property to the edge identified by the door number from current vertex.

Visualization methods

protected final void setDoorState(EdgeState st, int door);
Changes the door state and thus the edge color and thickness. The parameter st can be created using MarkedState or SyncState instances.

Communication methods

For communication purposes, each node identifies the path to its neighbors using "doors". A door is a unique integer identifier between 0 (included) and the number of neighbors minus one.

protected boolean sendTo(int door, Message msg);
Sends the message on outgoing door.

protected void sendAll(Message msg);
Sends the message to all neighbors.

protected Message receiveFrom(int door);
Gets the first message arriving on the specific door. The algorithm is blocked until reception.

protected Message receiveFrom(int door, MessageCriterion mc);
Gets the first message arriving on the specific door that matches the criterion mc. The algorithm is blocked until reception.

protected Message receive(Door door);
Gets the first message arriving on the node through the specific door. The algorithm is blocked until reception.

3.3.2 Synchronous algorithms

Synchronization methods

public int getPulse();
Gets the current pulse. This value is associated to the simulator, and thus shared by all running algorithms.

public int nextPulse();
The node asks for a new pulse to begin. The method waits until all algorithms have called this method.

Communication methods

protected boolean sendTo(int door, Message msg);
Stores the current pulse into the message, and sends the message on outgoing door.

protected final Message getNextMessage(DoorPulseCriterion dpc);
Gets the first message arriving that matches the criterion dpc. If no message has arrived, the algorithm does not block until reception but returns null.

protected final Message receive(Door door);
Returns the first message arrived in the previous pulse and writes the door number in the Door object.

protected final boolean existMessage(DoorPulseCriterion dpc);
Returns true if there exists a message that matches the dpc criterion in the message queue of the node.

protected final boolean anyMsg();
Returns true if the node has received any message which has been sent in the previous pulse.

3.3.3 Sensor algorithms

public void move(int sensorId);
Moves a sensor to a support vertex chosen by its associated mover.

public void moveAfterEnd(int sensorId);
Moves a sensor after algorithm end.

3.4 Compiling your agent or algorithm

Before you can compile your new java file, get the visidia_api.jar file, and suppose you put it in a directory referred to as $VISIDIA_API_PATH.
Then compile your file with the following command:

$ javac -classpath $VISIDIA_API_PATH/visidia_api.jar YourClass.java

 
You then run ViSiDiA as usual. When selecting an agent or an algorithm, click "Add new" in the selection dialog, and browse to YourClass.class. Select it, and you can execute it!

Note that you don’t need to add this class again (even if you close and restart ViSiDiA) except if you remove the class from the selection dialog.

3.5 API packages

3.5.1 Edge states

A process (algorithm or agent) may change the state of a graph edge. ViSiDiA offers marked (class MarkedState) and synchronized (class SynchronizedState) states. The user can define its own states by extending the class EdgeState.
One can find these classes in the visidia.simulation.process.edgestate package.

3.5.2 Messages

Algorithms send messages on the graph. ViSiDiA offers the possibility of sending messages representing integer values (class IntegerMessage), boolean values (class BooleanMessage), string values (class StringMessage), vectors of information of different types (class VectorMessage), and the information about a neighbor (class NeighborMessage). The user can define its own messages by extending the class Message.
One can find these classes in the visidia.simulation.process.messages package.

3.5.3 Criteria

An algorithm may decide to receive the messages complying with a number of criteria, for example by type (classes MessageCriterion, IntegerMessageCriterion, MessagePacketCriterion) or by provenance (classes DoorCriterion, DoorPulseCriterion). It is possible to have a criterion which is the combination of several others (class CompoundCriterion). The user can define its own criteria by extending the class Criterion.
One can find these classes in the visidia.simulation.process.criterion package.

3.6 Developing an algorithm: example of Rendez-Vous

3.6.1 Context

We have defined a non-oriented graph. The algorithm (the rendez-vous) is duplicated on each graph vertex. It means that each node executes the same algorithm, and that all executions are independent.

3.6.2 Algorithm description

Consider the algorithm on a given vertex V.
The algorithm randomly selects a neighbor N of V, then sends 1 to N and 0 to all other neighbors of V.
If at the same time V receives 1 from the algorithm on N, then we say that the rendez-vous is set between V and N.
When a rendez-vous is scheduled between two nodes, the edge connecting them is marked and algorithms on V and N send each other a "Hello" message. When both have received this message, the edge is unmarked.

3.6.3 Implementation using the API ViSiDiA

Randomly select a neighbor

We get the arity of V (its number of neighbors), and randomly choose a door (an integer value between 0 and the number of neighbors minus one).

int nbNeighbors = getArity();  
java.util.Random r = new java.util.Random();  
int neighborDoor = r.nextInt() % nbNeighbors;

Send synchronization messages (0 and 1)

We use the sendTo method with two parameters: the chosen door and an IntegerMessage.

for (int i = 0; i < nbNeighbors; ++i)  
    sendTo(i, new IntegerMessage(i == neighborDoor ? 1 : 0));

Receive a message

The method receiveFrom(door) waits for a message coming from door.

boolean rendezVousAccepted = false;  
for (int i = 0; i < nbNeighbors; ++i) {  
    IntegerMessage msg = (IntegerMessage) receiveFrom(i);  
    if ((i == neighborDoor) && (msg.value() == 1))  
        rendezVousAccepted = true;  
}

Mark an edge and send a "Hello" message

The method setDoorState changes the state of a given door; here we use a MarkedState (marked or unmarked depending on the boolean parameter).

if (rendezVousAccepted == true) {  
    setDoorState(new MarkedState(true), neighborDoor);  
    sendTo(neighborDoor, new StringMessage("Hello"));  
    receiveFrom(neighborDoor);  
    setDoorState(new MarkedState(false), neighborDoor);  
}

Remarks

3.6.4 Complete Java code

import visidia.simulation.process.algorithm.Algorithm;  
import visidia.simulation.process.edgestate.MarkedState;  
import visidia.simulation.process.messages.IntegerMessage;  
import visidia.simulation.process.messages.StringMessage;  
 
public class MyRendezVous extends Algorithm {  
 
    @Override  
    public Object clone() {  
        return new MyRendezVous();  
    }  
 
    @Override  
    public void init() {  
        java.util.Random r = new java.util.Random();  
        int nbNeighbors = getArity();  
 
        while (true) {  
            // Randomly select a neighbor  
            int neighborDoor = r.nextInt() % nbNeighbors;  
 
            // Send synchronization messages (0 and 1)  
            for (int i = 0; i < nbNeighbors; ++i)  
                sendTo(i, new IntegerMessage(i == neighborDoor ? 1 : 0));  
 
            // Receive a message  
            boolean rendezVousAccepted = false;  
            for (int i = 0; i < nbNeighbors; ++i) {  
                IntegerMessage msg = (IntegerMessage) receiveFrom(i);  
                if ((i == neighborDoor) && (msg.value() == 1))  
                    rendezVousAccepted = true;  
            }  
 
            // Mark an edge and send a "Hello" message  
            if (rendezVousAccepted == true) {  
                setDoorState(new MarkedState(true), neighborDoor);  
                sendTo(neighborDoor, new StringMessage("Hello"));  
                receiveFrom(neighborDoor);  
                setDoorState(new MarkedState(false), neighborDoor);  
            }  
        }  
    }  
 
}