Skip to content
Snippets Groups Projects
Commit 044e4b2a authored by Eddie Groh's avatar Eddie Groh
Browse files

Added betweeness centrality calculation

Issue-Ref: 4310
Issue-Url: af3#4310



Signed-off-by: default avatarEddie Groh <groh@fortiss.org>
parent 4708b508
No related branches found
No related tags found
1 merge request!210Setting up Metric extraction plugin for AF3 : Issue 4310
......@@ -40,6 +40,8 @@ public enum MetricKey {
SAFETY_LEVEL(false, true),
/** How deeply nested the corresponding element is */
NESTING_LEVEL(false),
/** The betweenness centrality of the corresponding element */
BETWEENESS_CENTRALITY(false),
//
// Metrics which are collected over all children nodes
......
......@@ -29,15 +29,25 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.fortiss.tooling.base.model.base.EntryConnectorBase;
import org.fortiss.tooling.base.model.base.ExitConnectorBase;
import org.fortiss.tooling.base.model.element.IConnection;
import org.fortiss.tooling.base.model.element.IConnector;
import org.fortiss.tooling.base.model.element.IHierarchicElement;
import org.fortiss.tooling.ext.quality.IMetricProvider;
import org.fortiss.tooling.ext.quality.data.MetricDataManager;
......@@ -189,6 +199,159 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider
}
manager.getHierarchicLookupTable().put(currentElement, node);
calculateBetweennessCentrality(currentElement, manager);
}
}
/**
* Creates a list of nodes contained in the graph centered around the provided element
* It will contain all elements contained within the provided element as well as all elements
* connected to the provided element
*
* @param scopeElement
* element defining the scope of the graph
* @return node list
*/
private static Set<IHierarchicElement> getLocalGraphView(IHierarchicElement scopeElement) {
// Create a view consisting of all nodes inside this element, as well as all elements
// connected to this element
// This ensures that elements inside this element communicating with elements outside
// this element are properly recognized
Set<IHierarchicElement> graphNodes = new HashSet<>();
graphNodes.addAll(scopeElement.getContainedElements());
// Collect all elements to which currentElement has a outgoing connection
for(ExitConnectorBase exitConnector : EcoreUtils.pickInstanceOf(ExitConnectorBase.class,
scopeElement.getConnectors())) {
for(IConnection exitConnection : exitConnector.getOutgoing()) {
graphNodes.add(exitConnection.getTarget().getOwner());
}
}
// Collect all elements to which currentElement has a incoming connection
for(EntryConnectorBase entryConnector : EcoreUtils.pickInstanceOf(EntryConnectorBase.class,
scopeElement.getConnectors())) {
for(IConnection entryConnection : entryConnector.getIncoming()) {
graphNodes.add(entryConnection.getSource().getOwner());
}
}
return graphNodes;
}
/**
* Calculates and saves the betweenness centrality of all elements contained inside the provided
* scopeElement
*
* @param scopeElement
* the scope of this calculation
* @param manager
* location to save the metrics
*/
private static void calculateBetweennessCentrality(IHierarchicElement scopeElement,
MetricDataManager manager) {
// Abort if no elements are found
if(!scopeElement.getContainedElements().isEmpty()) {
// Calculate betweenness centrality
Set<IHierarchicElement> graphNodes = getLocalGraphView(scopeElement);
// Initialize the betweenness values for all nodes to zero
Map<IHierarchicElement, Double> betweenness = new HashMap<>();
for(IHierarchicElement elementNode : graphNodes) {
betweenness.put(elementNode, 0.0);
}
// Iterate over all collected nodes
for(IHierarchicElement elementNode : graphNodes) {
// Initialize all variables
Stack<IHierarchicElement> stack = new Stack<>();
Map<IHierarchicElement, List<IHierarchicElement>> pred = new HashMap<>();
Map<IHierarchicElement, Integer> dist = new HashMap<>();
Map<IHierarchicElement, Double> sigma = new HashMap<>();
Queue<IHierarchicElement> queue = new LinkedList<>();
for(IHierarchicElement v : graphNodes) {
pred.put(v, new ArrayList<>());
dist.put(v, -1);
sigma.put(v, 0.0);
}
sigma.put(elementNode, 1.0);
dist.put(elementNode, 0);
queue.add(elementNode);
while(!queue.isEmpty()) {
IHierarchicElement v = queue.remove();
stack.push(v);
// Iterate over all connectors going out from the element
for(ExitConnectorBase exitConnectors : EcoreUtils
.pickInstanceOf(ExitConnectorBase.class, v.getConnectors())) {
// Iterate over all connections
for(IConnection outgoingConnection : exitConnectors.getOutgoing()) {
List<IHierarchicElement> targetElements = new ArrayList<>();
IHierarchicElement primaryTargetElement =
outgoingConnection.getTarget().getOwner();
// When we have a connection to the scopeElement, we have a connection
// leaving the local scope
if(scopeElement == primaryTargetElement) {
// Continue searching for outgoing connections on the target
// Connector
IConnector targetConnector = outgoingConnection.getTarget();
for(IConnection secondaryOutgoingConnection : targetConnector
.getOutgoing()) {
targetElements.add(
secondaryOutgoingConnection.getTarget().getOwner());
}
} else {
targetElements.add(primaryTargetElement);
}
for(IHierarchicElement targetElement : targetElements) {
// Check if element is in node list, to avoid creating data for
// nodes outside of our graph
if(graphNodes.contains(targetElement)) {
if(dist.get(targetElement) < 0) {
queue.add(targetElement);
dist.put(targetElement, dist.get(v) + 1);
}
if(dist.get(targetElement) == dist.get(v) + 1) {
sigma.put(targetElement,
sigma.get(targetElement) + sigma.get(v));
pred.get(targetElement).add(v);
}
}
}
}
}
}
// Initialize delta
Map<IHierarchicElement, Double> delta = new HashMap<>();
for(IHierarchicElement v : graphNodes) {
delta.put(v, 0.0);
}
while(!stack.isEmpty()) {
IHierarchicElement w = stack.pop();
for(IHierarchicElement v : pred.get(w)) {
double c = (sigma.get(v) / sigma.get(w)) * (1.0 + delta.get(w));
delta.put(v, delta.get(v) + c);
}
if(!w.equals(elementNode)) {
betweenness.put(w, betweenness.get(w) + delta.get(w));
}
}
}
// Save metric
for(IHierarchicElement child : scopeElement.getContainedElements()) {
manager.getHierarchicLookupTable().get(child).getStoredMetrics()
.put(MetricKey.BETWEENESS_CENTRALITY, betweenness.get(child));
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment