Commit eb264a39 authored by Thibaut Démare's avatar Thibaut Démare

Add the wiki into the git repo

parent 80abd89e
# The GAMA to Graphstream API
This guide contains specifications of all the primitives provided by the gs-gama plug-in. All arguments are given through the facets.
***Warning:*** The `(sourceId, timeId)` of the incoming and leaving events are shared by all the receivers and the senders. It means that if for example receiver1 receives an event coming from the node source with the identifier "foo" with timeId 4, and after that receiver2 receives an event coming from the same source with timeId 2, the second event will be ignored. The sourceId of the GAMA simulation is also taken into account, so the events generated by GAMA senders that come back to GAMA will also be ignored.
## Connect GAMA to Graphstream to send data: the `senders`
Senders connect a GAMA simulation to external receivers and send them graph events generated by the agents. Every agent can create or remove senders. Several senders can be created in the same simulation. For instance, one connected to a visualization application, another one connected to an analysis application and so on.
All senders share common `sourceId` which is automatically created when the extension is loaded. They also have a common timeline (a common `timeId` incremented at each event sent). In this way the whole Gama simulation is seen from outside as a unique source.
When a sender is created, agents can use it to send GraphStream events to external receivers. Each kind of agent can send any kind of events (graph, node, edge).
### Add a new connection to send data
`gs_add_sender` creates a sender. One unique graph is associated to a sender. Note that an external receiver must be connected on the other side before calling this command, otherwise a "connection refused error" occurs. If a sender with this identifier already exists, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_host`: a string, the name of the host to connect to
* `gs_port`: a number, the port of the host
### Close a connection
`gs_close` closes a sender. If the specified sender does not exist, an error occurs.
The mandatory parameter:
* `gs_sender_id`: a string, the unique identifier of the sender
### Clear all previous senders
`gs_clear_senders` disconnects and removes all the senders (if any) created with `gs_add_sender`. There is no parameter.
**Example**
```text
init {
// create a sender connected locally on port 2015
gs_add_sender gs_sender_id:"my_local_sender" gs_host:"localhost" gs_port:2015
// create a remote sender
gs_add_sender gs_sender_id:"my_remote_sender" gs_host:"yoda.galacticrepublic.gov" gs_port:4242
// close the sender "my_local_sender"
gs_close gs_sender_id:"my_local_sender";
// clear all existing senders
gs_clear_senders
}
```
## Send events
### Graph events
#### Add or modify an attribute on a graph
`gs_add_graph_attribute` adds an attribute on the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_attribute_name`: a string, the identifier of the graph attribute
* `gs_attribute_value`: a string or a double or an integer or a list of primitive values.
#### Remove an attribute on a graph
`gs_remove_graph_attribute` removes the attribute of the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_attribute_name`: a string, the identifier of the graph attribute
#### Define a step
`gs_step` send a step event to the graph associated to the specified sender. Graphstream defines the dynamic of a graph as a sequance of events. A step event indicates that previous events (for instance, nodes/edges deletion/addition) have been executed within the same period. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_step_number`: an integer
#### Clear a graph
`gs_clear` clears every previous events of the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
**Example**
```text
init {
// Open the connection
gs_add_sender gs_sender_id:"my_sender" gs_host:"localhost" gs_port:2016
// Add some attributes
gs_add_graph_attribute gs_sender_id:"my_sender" gs_attribute_name:"my_first_attribute" gs_attribute_value:"a string value";
gs_add_graph_attribute gs_sender_id:"my_sender" gs_attribute_name:"my_second_attribute" gs_attribute_value:12.34;
gs_add_graph_attribute gs_sender_id:"my_sender" gs_attribute_name:"my_third_attribute" gs_attribute_value:1;
gs_add_graph_attribute gs_sender_id:"my_sender" gs_attribute_name:"my_fourth_attribute" gs_attribute_value:[1,2,3];
// remove the attribute "my_attribute"
gs_remove_graph_attribute gs_sender_id:"my_sender" gs_attribute_name:"my_first_attribute";
// send a step event
gs_step gs_sender_id:"my_sender" gs_step_number:4;
// clear the graph
gs_clear gs_sender_id:"my_sender";
}
```
### Node events
#### Add a node
`gs_add_node` add a node to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_node_id`: a string, the unique identifier of the node in the graph.
#### Remove a node
`gs_remove_node` remove a node to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_node_id`: a string, the unique identifier of the node in the graph.
#### Add or modify an attribute on a node
`gs_add_node_attribute` add an attribute with its value to a node which belongs to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_node_id`: a string, the unique identifier of the node in the graph
* `gs_attribute_name`: a string, the identifier of the node attribute
* `gs_attribute_value`: a string or a double or an integer or a list of primitive values.
#### Remove an attribute on a node
`gs_remove_node_attribute` remove an attribute to a node which belongs to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_node_id`: a string, the unique identifier of the node in the graph
* `gs_attribute_name`: a string, the identifier of the node attribute.
**Example**
```text
init {
// Open the connection
gs_add_sender gs_sender_id:"my_sender" gs_host:"localhost" gs_port:2016
// Add a node
gs_add_node gs_sender_id:"my_sender" gs_node_id:"node1";
// Add some attributes
gs_add_node_attribute gs_sender_id:"my_sender" gs_node_id:"node1" gs_attribute_name:"my_first_attribute" gs_attribute_value:"a string value";
gs_add_node_attribute gs_sender_id:"my_sender" gs_node_id:"node1" gs_attribute_name:"my_second_attribute" gs_attribute_value:12.34;
gs_add_node_attribute gs_sender_id:"my_sender" gs_node_id:"node1" gs_attribute_name:"my_third_attribute" gs_attribute_value:1;
gs_add_node_attribute gs_sender_id:"my_sender" gs_node_id:"node1" gs_attribute_name:"my_fourth_attribute" gs_attribute_value:[1,2,3];
// Set an existing attribute
gs_add_node_attribute gs_sender_id:"my_sender" gs_node_id:"node1" gs_attribute_name:"my_third_attribute" gs_attribute_value:2;
// remove the attribute "my_attribute"
gs_remove_node_attribute gs_sender_id:"my_sender" gs_node_id:"node1" gs_attribute_name:"my_first_attribute";
}
```
### Edge events
#### Add an edge
`gs_add_edge` add an edge to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_edge_id`: a string, the unique identifier of the edge in the graph.
* `gs_node_id_from`: a string, the identifier of the first node.
* `gs_node_id_to`: a string, the identifier of the second node.
* `gs_is_directed`: a boolean, true if the edge is directed, false otherwise.
#### Remove an edge
`gs_remove_edge` remove an edge to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_edge_id`: a string, the unique identifier of the edge in the graph.
#### Add or modify an attribute on an edge
`gs_add_edge_attribute` add an attribute with its value to an edge which belongs to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_edge_id`: a string, the unique identifier of the edge in the graph
* `gs_attribute_name`: a string, the identifier of the node attribute
* `gs_attribute_value`: a string or a double or an integer or a list of primitive values.
#### Remove an attribute on an edge
`gs_remove_edge_attribute` remove an attribute to an edge which belongs to the graph associated to the specified sender. If the specified sender does not exist, an error occurs.
The mandatory parameters:
* `gs_sender_id`: a string, the unique identifier of the sender
* `gs_edge_id`: a string, the unique identifier of the edge in the graph
* `gs_attribute_name`: a string, the identifier of the node attribute.
**Example**
```text
init {
// Open the connection
gs_add_sender gs_sender_id:"my_sender" gs_host:"localhost" gs_port:2016
// Add two nodes
gs_add_node gs_sender_id:"my_sender" gs_node_id:"node1";
gs_add_node gs_sender_id:"my_sender" gs_node_id:"node2";
// Add a directed edge
gs_add_edge gs_sender_id:"my_sender" gs_edge_id:"edge1" gs_node_id_from:"node1" gs_node_id_to:"node2" gs_is_directed:true;
// Add some attributes
gs_add_edge_attribute gs_sender_id:"my_sender" gs_node_id:"edge1" gs_attribute_name:"my_first_attribute" gs_attribute_value:"a string value";
gs_add_edge_attribute gs_sender_id:"my_sender" gs_node_id:"edge1" gs_attribute_name:"my_second_attribute" gs_attribute_value:12.34;
gs_add_edge_attribute gs_sender_id:"my_sender" gs_node_id:"edge1" gs_attribute_name:"my_third_attribute" gs_attribute_value:1;
gs_add_edge_attribute gs_sender_id:"my_sender" gs_node_id:"edge1" gs_attribute_name:"my_fourth_attribute" gs_attribute_value:[1,2,3];
// Set an existing attribute
gs_add_edge_attribute gs_sender_id:"my_sender" gs_node_id:"edge1" gs_attribute_name:"my_third_attribute" gs_attribute_value:2;
// remove the attribute "my_attribute"
gs_remove_edge_attribute gs_sender_id:"my_sender" gs_node_id:"edge1" gs_attribute_name:"my_first_attribute";
}
```
## Connect GAMA to Graphstream to receive data: the `receivers`
Every GAMA agent can create and manage one or many receiver. Each receiver is runned in a separated thread and accumulates the received events. If the received event are not processed sometimes (or flushed), then a heap overflow will occurs.
### Add a new connection to receive data
`gs_add_receiver` opens a connection where a Graphstream-based application can be connected and send graph events to the GAMA simulation.
The mandatory parameters:
* `gs_receiver_id`: a string, the unique identifier of the receiver
* `gs_host`: a string, the name of the host to connect to
* `gs_port`: a number, the port of the host.
The optional parameter:
* `gs_attributes_filtered`: a list of string containing each attribute name that can be ignored be the receiver.
### Clear all previous receivers
`gs_clear_receivers` disconnects every existing receivers. There is no parameters.
### Clear the received flow of events
`gs_flush` deletes every received events of the specified receiver and which are waiting to be processed. If the specified receiver does not exist, an error occurs.
The mandatory parameter:
* `gs_receiver_id`: a string, the unique identifier of the receiver.
### Get the values of a graph attribute
`gs_get_graph_attribute` returns the list of every values taken by the given attribute of the graph associated with the specified receiver since the last call of this method, or since the last call of `gs_flush`. If the specified receiver does not exist, an error occurs.
The mandatory parameter:
* `gs_receiver_id`: a string, the unique identifier of the receiver
* `gs_attribute_name`: a string, the name of the attribute
* `returns`: a variable of type `list` that will contains the list of values of the attribute. The type of the values received must be primitive (string, double, integer, boolean, or an array of these primitives types).
### Get the values of a node attribute
`gs_get_node_attribute` returns the list of every values taken by the given attribute of the given node which belongs to the graph associated with the specified receiver since the last call of this method, or since the last call of `gs_flush`. If the specified receiver does not exist, an error occurs.
The mandatory parameter:
* `gs_receiver_id`: a string, the unique identifier of the receiver
* `gs_node_id`: a string, the unique identifier of the node in the graph
* `gs_attribute_name`: a string, the name of the attribute
* `returns`: a variable of type `list` that will contains the list of values of the attribute. The type of the values received must be primitive (string, double, integer, boolean, or an array of these primitives types).
### Get the values of an edge attribute
`gs_get_edge_attribute` returns the list of every values taken by the given attribute of the given edge which belongs to the graph associated with the specified receiver since the last call of this method, or since the last call of `gs_flush`. If the specified receiver does not exist, an error occurs.
The mandatory parameter:
* `gs_receiver_id`: a string, the unique identifier of the receiver
* `gs_edge_id`: a string, the unique identifier of the edge in the graph
* `gs_attribute_name`: a string, the name of the attribute
* `returns`: a variable of type `list` that will contains the list of values of the attribute. The type of the values received must be primitive (string, double, integer, boolean, or an array of these primitives types).
### Wait for the next step
`gs_wait_step` engages a blocking process allowing to synchronize GAMA with the Graphstream-based application. If the Graphstream-based application never send such an event, the primitive will never end and the simulation will be blocked. If the specified receiver does not exist, an error occurs.
The mandatory parameter:
* `gs_receiver_id`: a string, the unique identifier of the receiver
* `gs_return`: a variable of type double which will contains the value associated with the last step event received and not yet processed.
**Example**
```text
init {
// Open the conenction in order to receive data
gs_add_receiver gs_receiver_id:"my_receiver" gs_host:"localhost" gs_port:3001;
// Wait step in order to be synchronized with the Graphstream-based application
syncStep <- 0.0;
gs_wait_step gs_receiver_id:"my_receiver" gs_return:syncStep;
// Get graph attribute(s)
// It is assumed that the graph attribute "a" exists, otherwise, "val" will stay empty
list val <- [];
gs_get_graph_attribute gs_receiver_id:"my_receiver" gs_attribute_name:"a" returns:val;
int i<- 0;
loop while: i < length(val) {
write val[i];
i <- i + 1;
}
// Get node attribute(s)
// It is assumed that the node "node0" and its attribute "na" exist, otherwise, "val" will stay empty
val <- [];
gs_get_node_attribute gs_receiver_id:"my_receiver" gs_node_id:"node0" gs_attribute_name:"na" returns:val;
int i <- 0;
loop while: i < length(val) {
write val[i];
i <- i + 1;
}
// Get edge attribute(s)
// It is assumed that the edge "edge0_1" and its attribute "ea" exist, otherwise, "val" will stay empty
val <- [];
gs_get_edge_attribute gs_receiver_id:"my_receiver" gs_edge_id:"edge0_1" gs_attribute_name:"ea" returns:val;
i<- 0;
loop while: i < length(val) {
write val[i];
i <- i + 1;
}
// Flush the given receiver
gs_flush gs_receiver_id:"test2";
// Clear all receivers
gs_clear_receivers;
}
```
\ No newline at end of file
# The Graphstream to GAMA user guide
## How to receive events from a GAMA simulation
The main class used in this case is called `NetStreamReceiver`. It works as a server: you define a host and its port, and this class will listen the incoming events.
**The NetStreamReceiver:**
```java
// Open a connection on localhost on the port 2009
NetStreamReceiver receiver = new NetStreamReceiver("localhost", 2009);
```
After that, you need to use a sink in order to build a graph.
### The NetStreamViewer solution
Firstly, you can use a viewer which allows to display a graph. However this solution has some limitations since the viewer can not directly process algorithms on the graph or save it.
**The NetStreamViewer class**
```java
import org.graphstream.stream.netstream.NetStreamReceiver;
import org.graphstream.ui.swingViewer.Viewer;
public class NetStreamViewer extends Viewer {
public NetStreamViewer(NetStreamReceiver receiver) {
this(receiver, true);
}
public NetStreamViewer(NetStreamReceiver receiver, boolean autoLayout) {
super(receiver.getDefaultStream());
addDefaultView(true);
if (autoLayout)
enableAutoLayout();
}
public NetStreamViewer(NetStreamReceiver receiver, boolean autoLayout, int width, int height) {
this(receiver, autoLayout);
getDefaultView().resizeFrame(width, height);
}
}
```
**The main**
```java
import org.graphstream.stream.netstream.NetStreamReceiver;
public class MainReceiver {
public static void main(String[] args) throws UnknownHostException, IOException {
// Open a connection on localhost on the port 2009
NetStreamReceiver receiver = new NetStreamReceiver("localhost", 2009);
// Start the viewer
new NetStreamViewer(receiver, true);
}
}
```
### The Sink solution
The next solution is to define a `sink` to a graph. The graph will then be updated progressively with the incoming events.
**The `sink` associated to a graph:**
```java
// Open a connection on localhost on the port 2009
NetStreamReceiver receiver = new NetStreamReceiver("localhost", 2009);
// Instantiate a graph
SingleGraph graph = new SingleGraph("test", false, false);
// Add the sink
receiver.getDefaultStream().addSink(graph);
// The graph is now updated according to the received events
// In this case, the events are not pump automatically. We need to do it manually.
while(true){
receiver.getDefaultStream().pump();
// A sleep to avoid an overload of the CPU
Thread.sleep(1000);
}
```
The `sink` can be associated to numerous GraphStream class, other than a graph. For instance, it can be used to fill a file directly.
**The `sink` associated to a file:**
```java
// Open a connection on localhost on the port 2009
NetStreamReceiver receiver = new NetStreamReceiver("localhost", 2009);
// Create a file sink in order to save the events in the DGS format
FileSinkDGS fileSink = new FileSinkDGS();
// Add the sink
receiver.getDefaultStream().addSink(fileSink);
// Open the file and start to fill it according to the received events
try {
fileSink.begin(System.getProperty("user.dir" )+File.separator+"my_graph.dgs");
} catch (IOException e) {
e.printStackTrace();
}
// In this case, the events are not pump automatically. We need to do it manually.
while(true){
receiver.getDefaultStream().pump();
// The file must be flush sometimes due to the buffer limit
try {
fileSink.flush();
} catch (IOException e) {
e.printStackTrace();
}
// A sleep to avoid an overload of the CPU
Thread.sleep(1000);
}
```
Eventually, you also can used your own SinkAdapter and execute particular algorithms when specific events are received.
**The SaveWhenStepSinkAdapter class:** for instance, this class compute the betweenness centrality of the graph and save it in the [DGS format](http://graphstream-project.org/doc/Advanced-Concepts/The-DGS-File-Format_1.1/) at each step event received.
```java
import java.io.File;
import java.io.IOException;
import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.SingleGraph;
import org.graphstream.stream.SinkAdapter;
import org.graphstream.stream.netstream.NetStreamReceiver;
public class SaveWhenStepSinkAdapter extends SinkAdapter {
private Graph graph;
public SaveWhenStepSinkAdapter(NetStreamReceiver receiver) {
graph = new SingleGraph("my_graph", false, false);
receiver.getDefaultStream().addSink(graph);
receiver.getDefaultStream().addSink(this);
}
@Override
public void stepBegins(String sourceId, long timeId, double step) {
BetweennessCentrality bcb = new BetweennessCentrality();
bcb.setUnweighted();
bcb.setCentralityAttributeName("BetweennessCentrality");
bcb.init(graph);
bcb.compute();
try {
graph.write(System.getProperty("user.dir" )+File.separator+graph.getAttribute("name")+"_"+sourceId+"_"+timeId+"_"+step+".dgs");
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
## How to send events to a GAMA simulation
Theoretically, you just need to use the `NetStreamSender` class to send events to a GAMA simulation.
**The simplest way:**
```java
NetStreamSender sender = new NetStreamSender("localhost", 3001);
sender.stepBegins("foo", 0, 1);
sender.graphAttributeAdded("foo", 1, "an_attribute", 1);
sender.nodeAdded("foo", 2, "node1");
sender.nodeAdded("foo", 3, "node2");
sender.edgeAdded("foo", 4, "edge12", "node1", "node2", false);
sender.nodeAttributeAdded("foo", 5, "node1", "my_attribute", "my_value");
sender.edgeAttributeAdded("foo", 6, "edge12", "another_attribute", 1);
sender.close();
```
But you also can associate a `sink` between an object `graph` and the sender.
**The other way to make the same thing:**
```java
NetStreamSender sender = new NetStreamSender("localhost", 3001);
SingleGraph graph = new SingleGraph("foo");
graph.addSink(sender);
graph..stepBegins("foo", 0, 1);
graph.addAttribute("an_attribute", 1);
graph.addNode("node1");
graph.addNode("node2");
graph.addEdge("edge12", "node1", "node2", false);
graph.getNode("node1").addAttribute("my_attribute", "my_value");
graph.getEdge("edge12").addAttribute("another_attribute", 1);
sender.close();
```
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment