When designing a node algorithm, an important question is what communication primitives a node can use? For example, does the node know its neighbors? can a node detect new incident links? can a node read and/or write into the memory of its neighbors? should it rather exchange messages for all purposes?
While a large number of models exist, it is common to distinguish between two families of paradigms:
This tutorial gives an example for each paradigm, solving the same initial problem, called the Loner problem, where a node turns red when it has at least one neighbor, green otherwise (the node is a loner).
At the graph level, a node is directly aware of its incident links and adjacent neighbors. Technically, we allow the node to use the three following methods that allows, which one should consider as forbidden in message passing algorithms.
onLinkAdded()
: override this method to specify what a node does when an incident link is addedonLinkRemoved()
: override this method to specify what a node does when an incident link is removedgetNeighbors()
: retreives the list of nodes with whom the current node shares a linkimport io.jbotsim.core.Color;
import io.jbotsim.core.Link;
import io.jbotsim.core.Node;
public class LonerGraphBased extends Node{
@Override
public void onStart() {
if (getNeighbors().isEmpty()) {
setColor(Color.green);
} else {
setColor(Color.red);
}
}
@Override
public void onLinkAdded(Link link) {
setColor(Color.red);
}
@Override
public void onLinkRemoved(Link link) {
if (getNeighbors().isEmpty())
setColor(Color.green);
}
}
In the message passing version, the nodes are not immediately informed when a neighbors arrives or leaves. Instead, they rely on sending messages repeatedly to detect the presence of other nodes. A possible implementation of this principle is as follows:
import io.jbotsim.core.Color;
import io.jbotsim.core.Message;
import io.jbotsim.core.Node;
public class LonerMessageBased extends Node {
private boolean heardSomeone = false;
@Override
public void onClock(){
if (heardSomeone){
setColor(Color.red);
} else {
setColor(Color.green);
}
heardSomeone = false;
sendAll(new Message());
}
@Override
public void onMessage(Message msg) {
heardSomeone = true;
}
}
In both cases, think of telling the topology which of these classes is your default node model.
You may want to slow down the execution by calling setTimeUnit()
on your
Topology
object (in the main method).
We presented above two possible ways of solving the same problem, depending on whether we consider a graph-based model
or a message passing model. In many cases, the actual model lies between these two extremes.
For instance, it is common to assume that the nodes can identify their neighbors (or communication channels towards them).
In this case, looping over getNeighbors()
to send each neighbor a particular message seems reasonable.
Likewise, manipulating directly the node object of a neighbor is cheating in general, but the particular case of
calling getID()
on a neighbor when we assume that its identifier is known is reasonable too.
In summary, the polyvalence of JBotSim makes it extremely permissive. An algorithm designer can cheat in about all imaginable ways. We do not attempt to prevent this; rather, we consider that it is your responsibility to identify which primitives you can allow yourself, depending on the considered model.
So far, we have seen only distributed algorithms (a.k.a. node algorithms). The next tutorial will present how to code a Centralized Algorithm in JBotSim.