Documentation / Tutorials
Working with algorithms and generators
Algorithms
We see algorithms like something which can be initialized on a graph and then computed. For example, an algorithm can colorize nodes or edges of a graph ; an other can compute a spanned tree …
The org.graphstream.algorithm.Algorithm
interface defines the structure of
an algorithm. It contains two methods :
init( Graph g )
, which is the initialization step of the algorithm ;compute()
, which launches the algorithm.
Why does we not just use a compute(Graph)
method ?
The initialization step and computing step are located in different methods because you may have to make a new computation of your algorithm without calling the initialization step again. This initialization step must contain code which is unique for a graph and it has to be called again only if you want to reset data linked to the algorithm or to change the graph.
This is a good way to use algorithm:
Graph g = ... ;
// Creation of the graph
Algorithm a = ... ; // My algorithm
a.init(g);
a.compute();
// Others operations on g
a.compute(); // Update results
A basic algorithm example
The following is an example of a basic algorithm that computes min, max and average degree in the graph:
public class DegreesAlgorithm implements Algorithm {
Graph theGraph;
int minDegree, maxDegree, avgDegree;
public void init(Graph graph) {
theGraph = graph;
}
public void compute() {
avgDegree = 0;
minDegree = Integer.MAX_VALUE;
maxDegree = 0;
theGraph.nodes().forEach( n -> {
int deg = n.getDegree();
minDegree = Math.min(minDegree, deg);
maxDegree = Math.max(maxDegree, deg);
avgDegree += deg;
});
avgDegree /= theGraph.getNodeCount();
}
public int getMaxDegree() {
return maxDegree;
}
public int getMinDegree() {
return minDegree;
}
public int getAverageDegree() {
return avgDegree;
}
}
Dynamicity
On GraphStream, dynamicity is at the foreground so it is normal that algorithms
can be dynamic to. The interface org.graphstream.algorithm.DynamicAlgorithm
extends Algorithm
and introduces a new method terminate()
which defines
the end of the algorithm.
Use of this kind of algorithms could be:
Graph g = ... ;
// Creation of the graph
DynamicAlgorithm da = ... ;
da.init(g);
while( ... ) // something to do
da.compute();
da.terminate();
A basic dynamic algorithm example
In this example, computation is done continuously in a loop. One may want to make the computation when receiving events. This can be done with a Sink that will trigger the computation. For example, this is a dynamic algorithm where computation is done when a node is added:
public class ApparitionAlgorithm extends SinkAdapter implements
DynamicAlgorithm {
Graph theGraph;
HashMap<String, Integer> apparitions;
double avg;
public void init(Graph graph) {
theGraph = graph;
avg = 0;
graph.addSink(this);
}
public void compute() {
avg = 0;
for (int a : apparitions.values())
avg += a;
avg /= apparitions.size();
}
public void terminate() {
graph.removeSink(this);
}
public double getAverageApparitions() {
return avg;
}
public int getApparitions(String nodeId) {
return apparitions.get(nodeId);
}
public void nodeAdded(String sourceId, long timeId, String nodeId) {
int a = 0;
if (apparitions.containsKey(nodeId))
a = apparitions.get(nodeId);
apparitions.put(nodeId, a + 1);
}
public void stepBegins(String sourceId, long timeId, double step) {
compute();
}
}
In this last example, init(..)
is use to set a link between the graph and
the algorithm and end()
removes this link.
Generators
A generator is an algorithmic source of events that produce a graph according to criteria. Generators are composed of :
- a
begin()
method that is called one time at the beginning, - a
nextEvents()
that produces some new events and that can be called as much as more events are available, - a
end()
method that closes the generation.
A trivial example is a generator producing a full connected graph that adds a new node at each iteration and connects it with all previous nodes.
Generator is a Source, so transmission of events is done in the classic Source/Sink way:
Generator gen = ...;
Graph graph = ...;
gen.addSink(graph);
gen.begin();
for(int i = 0; i < 100; i++)
gen.nextEvents();
gen.end();
You can have a look on the overview on generators on this page.
A basic generator example
A basic full generator can be created easily :
public class MyFullGenerator extends SourceBase
implements Generator {
int currentIndex = 0;
int edgeId = 0;
public void begin() {
addNode();
}
public boolean nextEvents() {
addNode();
return true;
}
public void end() {
// Nothing to do
}
protected void addNode() {
sendNodeAdded(sourceId, Integer.toString(currentIndex));
for(int i = 0; i < currentIndex; i++)
sendEdgeAdded(sourceId, Integer.toString(edgeId++),
Integer.toString(i), Integer.toString(currentIndex), false);
currentIndex++;
}