未验证 提交 8ce9436f 编写于 作者: M Mathieu Bastian 提交者: GitHub

Merge pull request #2431 from gephi/statistical-inference

Add new community detection algorithm: Statistical inference
......@@ -176,6 +176,8 @@ public class StatisticsPanel extends JPanel {
Map<String, StatisticsCategory> cats = new LinkedHashMap<>();
cats.put(StatisticsUI.CATEGORY_NETWORK_OVERVIEW,
new StatisticsCategory(StatisticsUI.CATEGORY_NETWORK_OVERVIEW, 100));
cats.put(StatisticsUI.CATEGORY_COMMUNITY_DETECTION,
new StatisticsCategory(StatisticsUI.CATEGORY_COMMUNITY_DETECTION, 150));
cats.put(StatisticsUI.CATEGORY_NODE_OVERVIEW, new StatisticsCategory(StatisticsUI.CATEGORY_NODE_OVERVIEW, 200));
cats.put(StatisticsUI.CATEGORY_EDGE_OVERVIEW, new StatisticsCategory(StatisticsUI.CATEGORY_EDGE_OVERVIEW, 300));
cats.put(StatisticsUI.CATEGORY_DYNAMIC, new StatisticsCategory(StatisticsUI.CATEGORY_DYNAMIC, 400));
......
......@@ -64,6 +64,8 @@ public interface StatisticsUI {
String CATEGORY_NETWORK_OVERVIEW =
NbBundle.getMessage(StatisticsUI.class, "StatisticsUI.category.networkOverview");
String CATEGORY_COMMUNITY_DETECTION =
NbBundle.getMessage(StatisticsUI.class, "StatisticsUI.category.communityDetection");
String CATEGORY_NODE_OVERVIEW =
NbBundle.getMessage(StatisticsUI.class, "StatisticsUI.category.nodeOverview");
String CATEGORY_EDGE_OVERVIEW =
......@@ -128,6 +130,7 @@ public interface StatisticsUI {
* <li>{@link StatisticsUI#CATEGORY_NODE_OVERVIEW}</li>
* <li>{@link StatisticsUI#CATEGORY_EDGE_OVERVIEW}</li>
* <li>{@link StatisticsUI#CATEGORY_DYNAMIC}</li></ul>
* <li>{@link StatisticsUI#CATEGORY_COMMUNITY_DETECTION}</li></ul>
* Returns a custom String for defining a new category.
*
* @return this statistics' category
......
StatisticsUI.category.networkOverview= Network Overview
StatisticsUI.category.nodeOverview = Node Overview
StatisticsUI.category.edgeOverview = Edge Overview
StatisticsUI.category.dynamic = Dynamic
\ No newline at end of file
StatisticsUI.category.dynamic = Dynamic
StatisticsUI.category.communityDetection = Community Detection
\ No newline at end of file
/*
Copyright 2008-2011 Gephi
Authors : Mathieu Jacomy, Tiago Peixoto
Website : http://www.gephi.org
This file is part of Gephi.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2011 Gephi Consortium. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License. When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.
Contributor(s):
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.statistics.plugin;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.apache.commons.math3.special.Gamma;
import org.gephi.graph.api.Column;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Graph;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.Node;
import org.gephi.graph.api.NodeIterable;
import org.gephi.graph.api.Table;
import org.gephi.statistics.spi.Statistics;
import org.gephi.utils.longtask.spi.LongTask;
import org.gephi.utils.progress.Progress;
import org.gephi.utils.progress.ProgressTicket;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* @author Mathieu Jacomy & Tiago Peixoto
*/
public class StatisticalInferenceClustering implements Statistics, LongTask {
public static final String STAT_INF_CLASS = "stat_inf_class";
private final boolean useWeight = false;
private boolean isCanceled;
private StatisticalInferenceClustering.CommunityStructure structure;
private ProgressTicket progress;
private double descriptionLength;
private static double lBinom(double n, double m) {
return Gamma.logGamma(n + 1) - Gamma.logGamma(n - m + 1) - Gamma.logGamma(m + 1);
}
@Override
public boolean cancel() {
this.isCanceled = true;
return true;
}
@Override
public void setProgressTicket(ProgressTicket progressTicket) {
this.progress = progressTicket;
}
@Override
public void execute(GraphModel graphModel) {
Graph graph = graphModel.getUndirectedGraphVisible();
execute(graph);
}
public void execute(Graph graph) {
isCanceled = false;
graph.readLock();
try {
structure = new StatisticalInferenceClustering.CommunityStructure(graph);
int[] comStructure = new int[graph.getNodeCount()];
if (graph.getNodeCount() > 0) {//Fixes issue #713 Modularity Calculation Throws Exception On Empty Graph
HashMap<String, Double> computedStatInfMetrics =
computePartition(graph, structure, comStructure, useWeight);
descriptionLength = computedStatInfMetrics.get("descriptionLength");
} else {
descriptionLength = 0;
}
saveValues(comStructure, graph, structure);
} finally {
graph.readUnlock();
}
}
protected HashMap<String, Double> computePartition(Graph graph,
StatisticalInferenceClustering.CommunityStructure theStructure,
int[] comStructure,
boolean weighted) {
isCanceled = false;
Progress.start(progress);
Random rand = new Random();
HashMap<String, Double> results = new HashMap<>();
if (isCanceled) {
return results;
}
boolean someChange = true;
boolean initRound = true;
while (someChange) {
//System.out.println("Number of partitions: "+theStructure.communities.size());
someChange = false;
boolean localChange = true;
while (localChange) {
localChange = false;
int start = 0;
// Randomize
start = Math.abs(rand.nextInt()) % theStructure.N;
int step = 0;
for (int i = start; step < theStructure.N; i = (i + 1) % theStructure.N) {
step++;
StatisticalInferenceClustering.Community bestCommunity =
updateBestCommunity(theStructure, i, initRound);
if ((theStructure.nodeCommunities[i] != bestCommunity) && (bestCommunity != null)) {
//double S_before = computeDescriptionLength(graph, theStructure);
//System.out.println("Move node "+i+" to com "+bestCommunity.id+" : S_before="+S_before);
theStructure.moveNodeTo(i, bestCommunity);
//double S_after = computeDescriptionLength(graph, theStructure);
//System.out.println("Move node "+i+" to com "+bestCommunity.id+" : S_after="+S_after+ " (Diff = "+(S_after - S_before)+")");
localChange = true;
}
if (isCanceled) {
return results;
}
}
someChange = localChange || someChange;
initRound = false;
if (isCanceled) {
return results;
}
}
if (someChange) {
theStructure.zoomOut();
}
}
fillComStructure(graph, theStructure, comStructure);
double computedDescriptionLength = computeDescriptionLength(graph, theStructure);
results.put("descriptionLength", computedDescriptionLength);
return results;
}
public double delta(int node,
StatisticalInferenceClustering.Community community,
StatisticalInferenceClustering.CommunityStructure theStructure,
Double e_in,
Double e_out,
Double E,
Double B,
Double N
) {
//System.out.println("*** Compute delta for node "+node+" with respect to community "+community.id+" ***");
// Node degree
double k = theStructure.weights[node];
// Node weight: how many real nodes (not meta-nodes) the group represents
double nodeWeight = theStructure.graphNodeCount[node];
// Number of edges of target community (with itself or another one)
double e_r_target = community.weightSum;
// Number of edges within target community
Double e_rr_target = community.internalWeightSum;
// Number of real graph nodes of target community
int n_r_target = community.graphNodeCount;
// Number of edges of current (where the node belongs) community (with itself or another one)
double e_r_current = theStructure.nodeCommunities[node].weightSum;
// Number of edges within current community (where the node belongs)
Double e_rr_current = theStructure.nodeCommunities[node].internalWeightSum;
// Number of real graph nodes of current community
int n_r_current = theStructure.nodeCommunities[node].graphNodeCount;
// Description length: before
double S_b = 0.;
S_b -= Gamma.logGamma(e_out + 1);
if (e_out > 0) {
S_b += e_out * lBinom(B, 2);
}
S_b += Gamma.logGamma(e_r_current + 1);
S_b += Gamma.logGamma(e_r_target + 1);
S_b -= (e_rr_current) * Math.log(2) + Gamma.logGamma(e_rr_current + 1);
S_b -= (e_rr_target) * Math.log(2) + Gamma.logGamma(e_rr_target + 1);
S_b -= Gamma.logGamma(n_r_current + 1);
S_b -= Gamma.logGamma(n_r_target + 1);
S_b += lBinom(n_r_current + e_r_current - 1, e_r_current);
S_b += lBinom(n_r_target + e_r_target - 1, e_r_target);
S_b += lBinom(B + e_in - 1, e_in);
if (B > 1) {
S_b += Math.log(E + 1);
}
S_b += lBinom(N - 1, B - 1);
// Count the gains and losses
// -> loop over the neighbors
double delta_e_out = 0.;
double delta_e_in = 0.;
double delta_e_r_current = -k;
double delta_e_r_target = +k;
double delta_e_rr_current = 0.;
double delta_e_rr_target = 0.;
for (ComputationEdge e : theStructure.topology[node]) {
int nei = e.target;
Float w = e.weight;
if (nei == node) {
// Node self-loops
delta_e_rr_current -= w;
delta_e_rr_target += w;
} else {
// Losses (as if the node disappeared)
if (theStructure.nodeCommunities[node] == theStructure.nodeCommunities[nei]) {
// The neighbor is in current community, so
// the node will leave the neighbor's community
delta_e_rr_current -= w;
delta_e_in -= w;
} else {
// The neighbor is not in current community, so
// the node will not leave the neighbor's community
delta_e_out -= w;
}
// Gains (as if the node reappeared)
if (community == theStructure.nodeCommunities[nei]) {
// The neighbor is in target community, so
// the node will arrive in the neighbor's community
delta_e_rr_target += w; // add weight between node and community -> OK
delta_e_in += w;
} else {
// The neighbor is not in target community, so
// the node will not arrive in the neighbor's community
delta_e_out += w;
}
}
}
Double delta_B = 0.;
if (theStructure.nodeCommunities[node].weightSum == theStructure.weights[node]) {
// The node is the only one in the community
delta_B = -1.;
}
// Note: if it were possible to add the node to an empty group, we would have to check that
// the target group is empty or not, and if so, add one to delta_B.
// Description length: after
double S_a = 0.;
S_a -= Gamma.logGamma(e_out + delta_e_out + 1);
if (e_out + delta_e_out > 0) {
S_a += (e_out + delta_e_out) * lBinom(B + delta_B, 2);
}
S_a += Gamma.logGamma(e_r_target + delta_e_r_target + 1);
S_a -= (e_rr_target + delta_e_rr_target) * Math.log(2) + Gamma.logGamma(e_rr_target + delta_e_rr_target + 1);
S_a -= Gamma.logGamma(n_r_target + nodeWeight + 1);
S_a += lBinom(n_r_target + nodeWeight + e_r_target + delta_e_r_target - 1, e_r_target + delta_e_r_target);
if (delta_B == 0) {
// These calculations only apply if current category
// would still exist after moving the node
// (i.e. if it was not the last one)
S_a += Gamma.logGamma(e_r_current + delta_e_r_current + 1);
S_a -= (e_rr_current + delta_e_rr_current) * Math.log(2) +
Gamma.logGamma(e_rr_current + delta_e_rr_current + 1);
S_a -= Gamma.logGamma(n_r_current - nodeWeight + 1);
S_a +=
lBinom(n_r_current - nodeWeight + e_r_current + delta_e_r_current - 1, e_r_current + delta_e_r_current);
}
S_a += lBinom(B + delta_B + e_in + delta_e_in - 1, e_in + delta_e_in);
if (B + delta_B > 1) {
S_a += Math.log(E + 1);
}
S_a += lBinom(N - 1, B + delta_B - 1);
return S_a - S_b;
}
private StatisticalInferenceClustering.Community updateBestCommunity(
StatisticalInferenceClustering.CommunityStructure theStructure, int node_id, boolean initialization) {
// Total number of edges (graph size)
Double E = theStructure.graphWeightSum;
// Total number of edges from one community to the same one
Double e_in = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
// Total number of edges from one community to another
Double e_out = E - e_in;
// Total number of communities
Double B = (double) theStructure.communities.size();
// Total number of nodes (not metanodes!!!)
Double N = (double) theStructure.graph.getNodeCount();
//System.out.println("Test best community for node "+node_id+" (currently com "+theStructure.nodeCommunities[node_id].id+") Initialization: "+initialization);
double best = Double.MAX_VALUE;
StatisticalInferenceClustering.Community bestCommunity = null;
Set<StatisticalInferenceClustering.Community> iter = theStructure.nodeConnectionsWeight[node_id].keySet();
for (StatisticalInferenceClustering.Community com : iter) {
if (com != theStructure.nodeCommunities[node_id]) {
double deltaValue = delta(node_id, com, theStructure, e_in, e_out, E, B, N);
if (Double.isNaN(deltaValue)) {
// TODO: change this to an exception
System.out.println(
"WARNING - ALGO ERROR - Statistical inference - DELTA is NaN (this is not supposed to happen)");
}
//System.out.println("Node "+node_id+" => com "+com.id+" DELTA="+deltaValue);
if ((deltaValue < 0 || (initialization && Math.exp(-deltaValue) < Math.random())) &&
deltaValue < best) {
best = deltaValue;
bestCommunity = com;
}
}
}
if (bestCommunity == null) {
//System.out.println("(NO CHANGE) com "+theStructure.nodeCommunities[node_id].id);
bestCommunity = theStructure.nodeCommunities[node_id];
} else {
//System.out.println("Best community is "+bestCommunity.id);
}
return bestCommunity;
}
double computeDescriptionLength(Graph graph, StatisticalInferenceClustering.CommunityStructure theStructure) {
// Total number of edges (graph size)
double E = theStructure.graphWeightSum;
// Total number of edges from one community to the same one
double e_in = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
// Total number of edges from one community to another
double e_out = E - e_in;
// Total number of communities
Double B = (double) theStructure.communities.size();
// Total number of nodes (not metanodes!!!)
Double N = (double) theStructure.graph.getNodeCount();
// Description length
double S = 0.;
S -= Gamma.logGamma(e_out + 1);
if (e_out > 0) {
S += e_out * lBinom(B, 2);
}
for (Community community : theStructure.communities) {
// Number of edges of community (with itself or another one)
double e_r = community.weightSum;
// Number of edges within community
double e_rr = community.internalWeightSum;
// Number of nodes in the community
int n_r = community.graphNodeCount;
S += Gamma.logGamma(e_r + 1);
S -= (e_rr) * Math.log(2) + Gamma.logGamma(e_rr + 1);
S -= Gamma.logGamma(n_r + 1);
S += lBinom(n_r + e_r - 1, e_r);
}
S += lBinom(B + e_in - 1, e_in);
if (B > 1) {
S += Math.log(E + 1);
}
S += lBinom(N - 1, B - 1);
S += Gamma.logGamma(N + 1);
S += Math.log(N);
for (Node n : graph.getNodes()) {
// degree
double k = graph.getDegree(n);
S -= Gamma.logGamma(k + 1);
}
return S;
}
private int[] fillComStructure(Graph graph, StatisticalInferenceClustering.CommunityStructure theStructure,
int[] comStructure) {
int count = 0;
for (StatisticalInferenceClustering.Community com : theStructure.communities) {
for (Integer node : com.nodes) {
StatisticalInferenceClustering.Community hidden = theStructure.invMap.get(node);
for (Integer nodeInt : hidden.nodes) {
comStructure[nodeInt] = count;
}
}
count++;
}
return comStructure;
}
private void saveValues(int[] struct, Graph graph, StatisticalInferenceClustering.CommunityStructure theStructure) {
Table nodeTable = graph.getModel().getNodeTable();
Column modCol = nodeTable.getColumn(STAT_INF_CLASS);
if (modCol == null) {
modCol = nodeTable.addColumn(STAT_INF_CLASS, "Inferred Class", Integer.class, 0);
}
for (Node n : graph.getNodes()) {
int n_index = theStructure.map.get(n);
n.setAttribute(modCol, struct[n_index]);
}
}
@Override
public String getReport() {
//Distribution series
Map<Integer, Integer> sizeDist = new HashMap<>();
for (Node n : structure.graph.getNodes()) {
Integer v = (Integer) n.getAttribute(STAT_INF_CLASS);
if (!sizeDist.containsKey(v)) {
sizeDist.put(v, 0);
}
sizeDist.put(v, sizeDist.get(v) + 1);
}
XYSeries dSeries = ChartUtils.createXYSeries(sizeDist, "Size Distribution");
XYSeriesCollection dataset1 = new XYSeriesCollection();
dataset1.addSeries(dSeries);
JFreeChart chart = ChartFactory.createXYLineChart(
"Size Distribution",
"Stat Inf Class",
"Size (number of nodes)",
dataset1,
PlotOrientation.VERTICAL,
true,
false,
false);
chart.removeLegend();
ChartUtils.decorateChart(chart);
ChartUtils.scaleChart(chart, dSeries, false);
String imageFile = ChartUtils.renderChart(chart, "communities-size-distribution.png");
NumberFormat f = new DecimalFormat("#0.000");
String report = "<HTML> <BODY> <h1>Statistical Inference Report </h1> "
+ "<hr>"
+ "<br> <h2> Results: </h2>"
+ "Description Length: " + f.format(descriptionLength) + "<br>"
+ "Number of Communities: " + structure.communities.size()
+ "<br /><br />" + imageFile
+ "<br /><br />" + "<h2> Algorithm: </h2>"
+ "Statistical inference of assortative community structures<br />"
+ "Lizhi Zhang, Tiago P. Peixoto<br />"
+ "Phys. Rev. Research 2 043271 (2020)<br />"
+ "https://dx.doi.org/10.1103/PhysRevResearch.2.043271<br /><br />"
+ "<br /><br />"
+ "Bayesian stochastic blockmodeling<br />"
+ "Tiago P. Peixoto<br />"
+ "Chapter in “Advances in Network Clustering and Blockmodeling,” edited by<br />"
+ "P. Doreian, V. Batagelj, A. Ferligoj (Wiley, 2019)<br />"
+ "https://dx.doi.org/10.1002/9781119483298.ch11<br />"
+ "</BODY> </HTML>";
return report;
}
public double getDescriptionLength() {
return descriptionLength;
}
static class Community {
static int count = 0;
protected int id;
double weightSum; // e_r, i.e. sum of edge weights for the community, inside and outside altogether
// Note: here we count the internal edges twice
double internalWeightSum; // e_rr, i.e. sum of internal edge weights
int graphNodeCount; // How many real nodes (useful after zoomOut)
StatisticalInferenceClustering.CommunityStructure structure;
List<Integer> nodes;
HashMap<StatisticalInferenceClustering.Community, Float> connectionsWeight;
HashMap<StatisticalInferenceClustering.Community, Integer> connectionsCount;
public Community(StatisticalInferenceClustering.Community com) {
this.id = count++;
this.weightSum = 0;
structure = com.structure;
connectionsWeight = new HashMap<>();
connectionsCount = new HashMap<>();
nodes = new ArrayList<>();
}
public Community(StatisticalInferenceClustering.CommunityStructure structure) {
this.id = count++;
this.weightSum = 0;
this.structure = structure;
connectionsWeight = new HashMap<>();
connectionsCount = new HashMap<>();
nodes = new ArrayList<>();
}
public int size() {
return nodes.size();
}
public void seed(int node) {
nodes.add(node);
weightSum += structure.weights[node];
internalWeightSum += structure.internalWeights[node];
graphNodeCount += structure.graphNodeCount[node];
}
public boolean add(int node) {
nodes.add(node);
weightSum += structure.weights[node];
graphNodeCount += structure.graphNodeCount[node];
return true;
}
public boolean remove(int node) {
boolean result = nodes.remove((Integer) node);
weightSum -= structure.weights[node];
graphNodeCount -= structure.graphNodeCount[node];
if (nodes.isEmpty()) {
structure.communities.remove(this);
}
return result;
}
public String getMonitoring() {
String monitoring = "";
int count = 0;
for (int nodeIndex : nodes) {
if (count++ > 0) {
monitoring += " ";
}
monitoring += nodeIndex;
}
return monitoring;
}
}
class CommunityStructure {
HashMap<StatisticalInferenceClustering.Community, Float>[] nodeConnectionsWeight;
HashMap<StatisticalInferenceClustering.Community, Integer>[] nodeConnectionsCount;
HashMap<Node, Integer> map;
StatisticalInferenceClustering.Community[] nodeCommunities;
Graph graph;
double[] graphNodeCount; // number of graph nodes represented by that node
double[] weights; // The weighted degree of the nodes (in short)
double[] internalWeights; // The sum of internal edges weights
double graphWeightSum; // The weighted sum of degrees
List<ComputationEdge>[] topology;
List<StatisticalInferenceClustering.Community> communities;
int N;
HashMap<Integer, StatisticalInferenceClustering.Community> invMap;
CommunityStructure(Graph graph) {
//System.out.println("### INIT COMMUNITY STRUCTURE");
this.graph = graph;
N = graph.getNodeCount();
invMap = new HashMap<>();
// nodeConnectionsWeight is basically a table of, for each node, then for each community,
// how many connections they have.
nodeConnectionsWeight = new HashMap[N];
// nodeConnectionsCount is basically the same thing but unweighted. Remarkably, in case of parallel edges,
// but not taking weights into account, nodeConnectionsWeight will still count 1 for each parallel edges,
// while nodeConnectionsCount will count just 1.
nodeConnectionsCount = new HashMap[N];
// graphNodeCount is the number of real nodes (graph nodes) in each nodes. This is necessary because
// each node might in fact be a community of nodes (see zoomOut method)
graphNodeCount = new double[N];
// nodeCommunities is an index of which community each node belongs to
nodeCommunities = new StatisticalInferenceClustering.Community[N];
map = new HashMap<>(); // keeps track of the integer ids of the nodes
// The topology is basically an index of the outbound computation edges for each node
topology = new ArrayList[N];
communities = new ArrayList<>();
int index = 0;
weights = new double[N]; // The weight is basically the weighted degree of a node
internalWeights = new double[N];
NodeIterable nodesIterable = graph.getNodes();
for (Node node : nodesIterable) {
map.put(node, index);
nodeCommunities[index] = new StatisticalInferenceClustering.Community(this);
nodeConnectionsWeight[index] = new HashMap<>();
nodeConnectionsCount[index] = new HashMap<>();
weights[index] = 0; // Note: weight is degree, but we add that later on
graphNodeCount[index] = 1;
internalWeights[index] = 0;
nodeCommunities[index].seed(index);
StatisticalInferenceClustering.Community hidden =
new StatisticalInferenceClustering.Community(structure);
hidden.nodes.add(index);
invMap.put(index, hidden);
communities.add(nodeCommunities[index]);
index++;
if (isCanceled) {
nodesIterable.doBreak();
return;
}
}
int[] edgeTypes = graph.getModel().getEdgeTypes();
nodesIterable = graph.getNodes();
for (Node node : nodesIterable) {
int node_index = map.get(node);
StatisticalInferenceClustering.Community com = nodeCommunities[node_index];
topology[node_index] = new ArrayList<>();
Set<Node> uniqueNeighbors = new HashSet<>(graph.getNeighbors(node).toCollection());
for (Node neighbor : uniqueNeighbors) {
if (node == neighbor) {
continue;
}
int neighbor_index = map.get(neighbor);
float weight = 0;
//Sum all parallel edges weight:
for (int edgeType : edgeTypes) {
for (Edge edge : graph.getEdges(node, neighbor, edgeType)) {
if (useWeight) {
// TODO: the algorithm only works with integer weights
//weight += edge.getWeight(graph.getView());
} else {
weight += 1;
}
}
}
//Finally add a single edge with the summed weight of all parallel edges:
//Fixes issue #1419 Getting null pointer error when trying to calculate modularity
weights[node_index] += weight;
com.weightSum += weight;
if (node_index == neighbor_index) {
internalWeights[node_index] += weight;
}
ComputationEdge ce = new ComputationEdge(node_index, neighbor_index, weight);
topology[node_index].add(ce);
StatisticalInferenceClustering.Community adjCom = nodeCommunities[neighbor_index];
//System.out.println("Add links from node "+node_index+" to community "+adjCom.id);
nodeConnectionsWeight[node_index].put(adjCom, weight);
nodeConnectionsCount[node_index].put(adjCom, 1);
StatisticalInferenceClustering.Community nodeCom = nodeCommunities[node_index];
//System.out.println("Add links from community "+nodeCom.id+" to community "+adjCom.id);
nodeCom.connectionsWeight.put(adjCom, weight);
nodeCom.connectionsCount.put(adjCom, 1);
//System.out.println("Add links from node "+neighbor_index+" to community "+nodeCom.id);
nodeConnectionsWeight[neighbor_index].put(nodeCom, weight);
nodeConnectionsCount[neighbor_index].put(nodeCom, 1);
//System.out.println("Add links from community "+adjCom.id+" to community "+nodeCom.id);
adjCom.connectionsWeight.put(nodeCom, weight);
adjCom.connectionsCount.put(nodeCom, 1);
graphWeightSum += weight;
}
if (isCanceled) {
nodesIterable.doBreak();
return;
}
}
graphWeightSum /= 2.0;
}
private void addNodeTo(int node, StatisticalInferenceClustering.Community to) {
//System.out.println("### ADD NODE "+node+" TO COMMUNITY "+to.id);
to.add(node);
nodeCommunities[node] = to;
for (ComputationEdge e : topology[node]) {
int neighbor = e.target;
////////
//Add Node Connection to this community
//System.out.println("Add links from node "+neighbor+" to community "+to.id);
//System.out.println("Add links from node "+neighbor+" to community "+to.id);
nodeConnectionsWeight[neighbor].merge(to, e.weight, Float::sum);
nodeConnectionsCount[neighbor].merge(to, 1, Integer::sum);
///////////////////
StatisticalInferenceClustering.Community adjCom = nodeCommunities[neighbor];
//System.out.println("Add links from community "+adjCom.id+" to community "+to.id);
//System.out.println("Add links from community "+adjCom.id+" to community "+to.id);
adjCom.connectionsWeight.merge(to, e.weight, Float::sum);
adjCom.connectionsCount.merge(to, 1, Integer::sum);
if (node == neighbor) {
continue;
}
//System.out.println("Add links from node "+node+" to community "+adjCom.id);
//System.out.println("Add links from node "+node+" to community "+adjCom.id);
nodeConnectionsWeight[node].merge(adjCom, e.weight, Float::sum);
nodeConnectionsCount[node].merge(adjCom, 1, Integer::sum);
if (to != adjCom) {
//System.out.println("Add links from community "+to.id+" to community "+adjCom.id);
//System.out.println("Add links from community "+to.id+" to community "+adjCom.id);
to.connectionsWeight.merge(adjCom, e.weight, Float::sum);
to.connectionsCount.merge(adjCom, 1, Integer::sum);
}
}
to.internalWeightSum += nodeConnectionsWeight[node].getOrDefault(to, 0.f);
}
private void removeNodeFromItsCommunity(int node) {
//System.out.println("### REMOVE NODE FROM ITS COMMUNITY "+node);
StatisticalInferenceClustering.Community community = nodeCommunities[node];
community.internalWeightSum -= nodeConnectionsWeight[node].getOrDefault(community, 0.f);
for (ComputationEdge e : topology[node]) {
int neighbor = e.target;
////////
//Remove Node Connection to this community
Float edgesTo = nodeConnectionsWeight[neighbor].get(community);
Integer countEdgesTo = nodeConnectionsCount[neighbor].get(community);
if (countEdgesTo - 1 == 0) {
//System.out.println("REMOVE links from node "+neighbor+" to community "+community.id);
nodeConnectionsWeight[neighbor].remove(community);
nodeConnectionsCount[neighbor].remove(community);
} else {
//System.out.println("Add links from node "+neighbor+" to community "+community.id);
nodeConnectionsWeight[neighbor].put(community, edgesTo - e.weight);
nodeConnectionsCount[neighbor].put(community, countEdgesTo - 1);
}
///////////////////
//Remove Adjacent Community's connection to this community
StatisticalInferenceClustering.Community adjCom = nodeCommunities[neighbor];
Float oEdgesto = adjCom.connectionsWeight.get(community);
Integer oCountEdgesto = adjCom.connectionsCount.get(community);
if (oCountEdgesto - 1 == 0) {
//System.out.println("Remove links from community "+adjCom.id+" to community "+community.id+" *");
adjCom.connectionsWeight.remove(community);
adjCom.connectionsCount.remove(community);
} else {
//System.out.println("Remove links from community "+adjCom.id+" to community "+community.id);
adjCom.connectionsWeight.put(community, oEdgesto - e.weight);
adjCom.connectionsCount.put(community, oCountEdgesto - 1);
}
if (node == neighbor) {
continue;
}
if (adjCom != community) {
Float comEdgesto = community.connectionsWeight.get(adjCom);
Integer comCountEdgesto = community.connectionsCount.get(adjCom);
if (comCountEdgesto - 1 == 0) {
//System.out.println("Remove links from community "+community.id+" to community "+adjCom.id+" *");
community.connectionsWeight.remove(adjCom);
community.connectionsCount.remove(adjCom);
} else {
//System.out.println("Remove links from community "+community.id+" to community "+adjCom.id);
community.connectionsWeight.put(adjCom, comEdgesto - e.weight);
community.connectionsCount.put(adjCom, comCountEdgesto - 1);
}
}
Float nodeEgesTo = nodeConnectionsWeight[node].get(adjCom);
Integer nodeCountEgesTo = nodeConnectionsCount[node].get(adjCom);
if (nodeCountEgesTo - 1 == 0) {
//System.out.println("REMOVE links from node "+node+" to community "+adjCom.id+ " *");
nodeConnectionsWeight[node].remove(adjCom);
nodeConnectionsCount[node].remove(adjCom);
} else {
//System.out.println("REMOVE links from node "+node+" to community "+adjCom.id);
nodeConnectionsWeight[node].put(adjCom, nodeEgesTo - e.weight);
nodeConnectionsCount[node].put(adjCom, nodeCountEgesTo - 1);
}
}
community.remove(node);
}
private void moveNodeTo(int node, StatisticalInferenceClustering.Community to) {
//System.out.println("### MOVE NODE "+node+" TO COM "+to.id);
removeNodeFromItsCommunity(node);
addNodeTo(node, to);
}
protected void _moveNodeTo(int node, StatisticalInferenceClustering.Community to) {
// NOTE: THIS IS FOR UNIT TEST PURPOSE ONLY
moveNodeTo(node, to);
}
protected void _zoomOut() {
// NOTE: THIS IS FOR UNIT TEST PURPOSE ONLY
zoomOut();
}
private void zoomOut() {
//System.out.println("### ZOOM OUT");
int M = communities.size();
// The new topology uses preexisting communities as nodes
ArrayList<ComputationEdge>[] newTopology = new ArrayList[M];
int index = 0;
// nodeCommunities is an index of the communities per node.
// In this context, the preexisting communities will become the nodes
// of new upper-level communities (meta-communities).
nodeCommunities = new StatisticalInferenceClustering.Community[M];
nodeConnectionsWeight = new HashMap[M];
nodeConnectionsCount = new HashMap[M];
double[] oldGraphNodeCount = graphNodeCount.clone();
HashMap<Integer, StatisticalInferenceClustering.Community> newInvMap = new HashMap<>();
for (int i = 0; i < communities.size(); i++) {
// For each community "com", that we want to transform into a node in the new topology...
StatisticalInferenceClustering.Community com = communities.get(i);
nodeConnectionsWeight[index] = new HashMap<>();
nodeConnectionsCount[index] = new HashMap<>();
newTopology[index] = new ArrayList<>();
// For each community "com", we create a meta-community nodeCommunities[index] containing only it
nodeCommunities[index] = new StatisticalInferenceClustering.Community(com);
// iter is the set of communities with which com has (weighted) links.
Set<StatisticalInferenceClustering.Community> iter = com.connectionsWeight.keySet();
// weightSum is the number of edges from the community (into itself or not)
double weightSum = 0;
double graphNodeSum = 0;
StatisticalInferenceClustering.Community hidden =
new StatisticalInferenceClustering.Community(structure);
for (Integer nodeInt : com.nodes) {
graphNodeSum += oldGraphNodeCount[nodeInt];
StatisticalInferenceClustering.Community oldHidden = invMap.get(nodeInt);
hidden.nodes.addAll(oldHidden.nodes);
}
newInvMap.put(index, hidden);
for (StatisticalInferenceClustering.Community adjCom : iter) {
// adjCom is an adjacent community to com
int target = communities.indexOf(adjCom);
float weight = com.connectionsWeight.get(adjCom);
if (target == index) {
weightSum += 2. * weight;
} else {
weightSum += weight;
}
ComputationEdge e = new ComputationEdge(index, target, weight);
newTopology[index].add(e);
}
weights[index] = weightSum;
graphNodeCount[index] = graphNodeSum;
internalWeights[index] = com.internalWeightSum;
nodeCommunities[index].seed(index);
index++;
}
communities.clear();
for (int i = 0; i < M; i++) {
StatisticalInferenceClustering.Community com = nodeCommunities[i];
communities.add(com);
for (ComputationEdge e : newTopology[i]) {
//System.out.println("Add links from node "+i+" to community "+nodeCommunities[e.target].id);
nodeConnectionsWeight[i].put(nodeCommunities[e.target], e.weight);
nodeConnectionsCount[i].put(nodeCommunities[e.target], 1);
//System.out.println("Add links from community "+com.id+" to community "+nodeCommunities[e.target].id);
com.connectionsWeight.put(nodeCommunities[e.target], e.weight);
com.connectionsCount.put(nodeCommunities[e.target], 1);
}
}
N = M;
topology = newTopology;
invMap = newInvMap;
}
public String getMonitoring() {
String monitoring = "";
for (StatisticalInferenceClustering.Community com : communities) {
monitoring += "com" + com.id + "[";
int count = 0;
for (Integer node : com.nodes) {
StatisticalInferenceClustering.Community hidden = invMap.get(node);
if (count++ > 0) {
monitoring += " ";
}
monitoring += "n" + node + "(" + hidden.getMonitoring() + ")";
}
monitoring += "] ";
}
return monitoring;
}
// Useful for monitoring and debugging
public boolean checkIntegrity() {
boolean integrity = true;
Double E = graphWeightSum;
Double e_in = communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
Double e_out = E - e_in;
Double B = Double.valueOf(communities.size());
Double N = Double.valueOf(graph.getNodeCount());
// Check the integrity of nodeConnectionsWeight
double nodeComWeightSum = 0;
for (int node = 0; node < nodeConnectionsWeight.length; node++) {
HashMap<StatisticalInferenceClustering.Community, Float> hm = nodeConnectionsWeight[node];
Collection<Float> values = hm.values();
nodeComWeightSum += values.stream().mapToDouble(v -> (double) v).sum();
}
// TODO: what should be done, in fact,
// is to check that for each node the sum of nodeConnectionsWeight
// equals its degree.
return integrity;
}
}
static class ComputationEdge {
int source;
int target;
float weight;
public ComputationEdge(int s, int t, float w) {
source = s;
target = t;
weight = w;
}
}
}
/*
Copyright 2008-2011 Gephi
Authors : Mathieu Jacomy, Tiago Peixoto
Website : http://www.gephi.org
This file is part of Gephi.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2011 Gephi Consortium. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License. When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.
Contributor(s):
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.statistics.plugin.builder;
import org.gephi.statistics.plugin.StatisticalInferenceClustering;
import org.gephi.statistics.spi.Statistics;
import org.gephi.statistics.spi.StatisticsBuilder;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
/**
* @author Mathieu Jacomy & Tiago Peixoto
*/
@ServiceProvider(service = StatisticsBuilder.class)
public class StatisticalInferenceBuilder implements StatisticsBuilder {
@Override
public String getName() {
return NbBundle.getMessage(StatisticalInferenceBuilder.class, "StatisticalInference.name");
}
@Override
public Statistics getStatistics() {
return new StatisticalInferenceClustering();
}
@Override
public Class<? extends Statistics> getStatisticsClass() {
return StatisticalInferenceClustering.class;
}
}
......@@ -3,6 +3,7 @@ ClusteringCoefficent.name=Clustering Coefficient
GraphDistance.name=Graph Distance
DegreeDistribution.name=Degree Distribution
Modularity.name=Modularity
StatisticalInference.name=Stat. Inference Clustering
PageRank.name=Page Rank
Hits.name=HITS
InOutDegree.name=InOut Degree
......
/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2011 Gephi Consortium. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License. When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.
Contributor(s):
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.statistics.plugin;
import java.util.ArrayList;
import java.util.HashMap;
import junit.framework.TestCase;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.Node;
import org.gephi.graph.api.NodeIterable;
import org.gephi.graph.api.UndirectedGraph;
import org.gephi.io.importer.GraphImporter;
import org.junit.Test;
/**
* @author Mathieu Jacomy
*/
public class StatisticalInferenceTest extends TestCase {
private UndirectedGraph getCliquesBridgeGraph() {
GraphModel graphModel = GraphModel.Factory.newInstance();
UndirectedGraph undirectedGraph = graphModel.getUndirectedGraph();
Node node0 = graphModel.factory().newNode("0");
Node node1 = graphModel.factory().newNode("1");
Node node2 = graphModel.factory().newNode("2");
Node node3 = graphModel.factory().newNode("3");
Node node4 = graphModel.factory().newNode("4");
Node node5 = graphModel.factory().newNode("5");
Node node6 = graphModel.factory().newNode("6");
Node node7 = graphModel.factory().newNode("7");
undirectedGraph.addNode(node0);
undirectedGraph.addNode(node1);
undirectedGraph.addNode(node2);
undirectedGraph.addNode(node3);
undirectedGraph.addNode(node4);
undirectedGraph.addNode(node5);
undirectedGraph.addNode(node6);
undirectedGraph.addNode(node7);
// Clique A
Edge edge01 = graphModel.factory().newEdge(node0, node1, false);
Edge edge12 = graphModel.factory().newEdge(node1, node2, false);
Edge edge23 = graphModel.factory().newEdge(node2, node3, false);
Edge edge30 = graphModel.factory().newEdge(node3, node0, false);
Edge edge02 = graphModel.factory().newEdge(node0, node2, false);
Edge edge13 = graphModel.factory().newEdge(node1, node3, false);
// Bridge
Edge edge04 = graphModel.factory().newEdge(node0, node4, false);
// Clique B
Edge edge45 = graphModel.factory().newEdge(node4, node5, false);
Edge edge56 = graphModel.factory().newEdge(node5, node6, false);
Edge edge67 = graphModel.factory().newEdge(node6, node7, false);
Edge edge74 = graphModel.factory().newEdge(node7, node4, false);
Edge edge46 = graphModel.factory().newEdge(node4, node6, false);
Edge edge57 = graphModel.factory().newEdge(node5, node7, false);
undirectedGraph.addEdge(edge01);
undirectedGraph.addEdge(edge12);
undirectedGraph.addEdge(edge23);
undirectedGraph.addEdge(edge30);
undirectedGraph.addEdge(edge02);
undirectedGraph.addEdge(edge13);
undirectedGraph.addEdge(edge04);
undirectedGraph.addEdge(edge45);
undirectedGraph.addEdge(edge56);
undirectedGraph.addEdge(edge67);
undirectedGraph.addEdge(edge74);
undirectedGraph.addEdge(edge46);
undirectedGraph.addEdge(edge57);
UndirectedGraph graph = graphModel.getUndirectedGraph();
return graph;
}
@Test
public void testCliquesBridgeGraph_descriptionLength() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// At initialization, each node is in its own community.
// Here we just test the description length at init.
// We test for the know value (from GraphTools)
double descriptionLength_atInit = sic.computeDescriptionLength(graph, theStructure);
assertEquals(36.0896, descriptionLength_atInit, 0.0001);
// Now we move the nodes so that one community remains for each clique
StatisticalInferenceClustering.Community cA = theStructure.nodeCommunities[0];
StatisticalInferenceClustering.Community cB = theStructure.nodeCommunities[4];
theStructure._moveNodeTo(1, cA);
theStructure._moveNodeTo(2, cA);
theStructure._moveNodeTo(3, cA);
theStructure._moveNodeTo(5, cB);
theStructure._moveNodeTo(6, cB);
theStructure._moveNodeTo(7, cB);
// Now we test that the description length is shorter when the communities
// match the expectations (one community per clique)
double descriptionLength_atIdealPartition = sic.computeDescriptionLength(graph, theStructure);
assertTrue(descriptionLength_atIdealPartition < descriptionLength_atInit);
}
@Test
public void testDescriptionLengthOneCommunity() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// Now we move the nodes in the same community
StatisticalInferenceClustering.Community com = theStructure.nodeCommunities[0];
theStructure._moveNodeTo(1, com);
theStructure._moveNodeTo(2, com);
theStructure._moveNodeTo(3, com);
theStructure._moveNodeTo(4, com);
theStructure._moveNodeTo(5, com);
theStructure._moveNodeTo(6, com);
theStructure._moveNodeTo(7, com);
// Now we test that the description length is shorter when the communities
// match the expectations (one community per clique)
double descriptionLength = sic.computeDescriptionLength(graph, theStructure);
assertEquals(29.93900552172898, descriptionLength, 0.0001);
// Zoom out
theStructure._zoomOut();
descriptionLength = sic.computeDescriptionLength(graph, theStructure);
assertEquals(29.93900552172898, descriptionLength, 0.0001);
}
@Test
public void testCommunityWeightsBookkeeping() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// Note: at initialization, each node is in its own community.
for (int node = 0; node < 8; node++) {
// The community for each node should have a weight equal to the degree of that node.
assertEquals(theStructure.weights[node], theStructure.nodeCommunities[node].weightSum);
// The community for each node should have an inner weight equal to zero.
assertEquals(0., theStructure.nodeCommunities[node].internalWeightSum);
}
// Move node 1 to the same community as node 0: it now contains nodes 0 and 1 (degrees 4 and 3).
theStructure._moveNodeTo(1, theStructure.nodeCommunities[0]);
assertEquals(7., theStructure.nodeCommunities[0].weightSum);
// There is 1 internal link
assertEquals(1., theStructure.nodeCommunities[0].internalWeightSum);
// Move node 1 to the same community as node 2: now, the community of node 0 contains just nodes 0 (degree 4).
theStructure._moveNodeTo(1, theStructure.nodeCommunities[2]);
assertEquals(4., theStructure.nodeCommunities[0].weightSum);
// There is 0 internal link
assertEquals(0., theStructure.nodeCommunities[0].internalWeightSum);
}
@Test
public void testMiscMetricsBookkeeping() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// Note: at initialization, each node is in its own community.
// We move the nodes to just two communities, one for each clique.
StatisticalInferenceClustering.Community cA = theStructure.nodeCommunities[0];
StatisticalInferenceClustering.Community cB = theStructure.nodeCommunities[4];
theStructure._moveNodeTo(1, cA);
theStructure._moveNodeTo(2, cA);
theStructure._moveNodeTo(3, cA);
theStructure._moveNodeTo(5, cB);
theStructure._moveNodeTo(6, cB);
theStructure._moveNodeTo(7, cB);
// Total number of edges (graph size)
Double E = theStructure.graphWeightSum;
assertEquals(13., E);
// Total number of edges from one community to the same one
Double e_in = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
assertEquals(12., e_in); // 6 inner links per clique
// Total number of edges from one community to another
Double e_out = E - e_in;
assertEquals(1., e_out); // 1 bridge
// Total number of communities
Double B = Double.valueOf(theStructure.communities.size());
assertEquals(2., B);
// Total number of nodes (not metanodes!!!)
Double N = Double.valueOf(theStructure.graph.getNodeCount());
assertEquals(8., N);
}
@Test
public void testSimpleDescriptionLengthDelta() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// Note: at initialization, each node is in its own community.
// Compute description length
double descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
// Test moving node 1 to the same community as node 0
int node = 1;
StatisticalInferenceClustering.Community community = theStructure.nodeCommunities[0]; // Node 0's community
// Benchmark the delta
Double E = theStructure.graphWeightSum;
Double e_in = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
Double e_out = E - e_in;
Double B = Double.valueOf(theStructure.communities.size());
Double N = Double.valueOf(theStructure.graph.getNodeCount());
double descriptionLength_delta = sic.delta(node, community, theStructure, e_in, e_out, E, B, N);
// Actually move the node
theStructure._moveNodeTo(node, community);
// Compute description length again
double descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
// Delta should be (approximately) equal to the difference
assertEquals(descriptionLength_after - descriptionLength_before, descriptionLength_delta, 0.0001);
}
@Test
public void testDescriptionLengthDeltaWithZoomOut() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// Make some groups and zoom out.
theStructure._moveNodeTo(1, theStructure.nodeCommunities[0]);
theStructure._moveNodeTo(2, theStructure.nodeCommunities[0]);
theStructure._zoomOut();
theStructure._moveNodeTo(2, theStructure.nodeCommunities[0]);
theStructure._moveNodeTo(3, theStructure.nodeCommunities[1]);
// Compute description length
double descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
int node = 1;
StatisticalInferenceClustering.Community community = theStructure.nodeCommunities[0]; // Node 0's community
// Benchmark the delta
Double E = theStructure.graphWeightSum;
Double e_in = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
Double e_out = E - e_in;
Double B = Double.valueOf(theStructure.communities.size());
Double N = Double.valueOf(theStructure.graph.getNodeCount());
double descriptionLength_delta = sic.delta(node, community, theStructure, e_in, e_out, E, B, N);
// Actually move the node
theStructure._moveNodeTo(node, community);
// Compute description length again
double descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
// Delta should be (approximately) equal to the difference
assertEquals(descriptionLength_after - descriptionLength_before, descriptionLength_delta, 0.0001);
}
@Test
public void testDescriptionLengthDeltaWithZoomOut_x2() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// Make some groups and shuffle around to stress bookkeeping
theStructure._moveNodeTo(4, theStructure.nodeCommunities[0]);
theStructure._moveNodeTo(5, theStructure.nodeCommunities[1]);
theStructure._moveNodeTo(6, theStructure.nodeCommunities[2]);
theStructure._moveNodeTo(1, theStructure.nodeCommunities[0]);
theStructure._moveNodeTo(4, theStructure.nodeCommunities[5]);
theStructure._moveNodeTo(2, theStructure.nodeCommunities[3]);
theStructure._moveNodeTo(6, theStructure.nodeCommunities[7]);
//System.out.println(theStructure.getMonitoring());
// > com0[n0(0) n1(1)] com2[n5(5) n4(4)] com6[n3(3) n2(2)] com14[n7(7) n6(6)]
// Zoom out
theStructure._zoomOut();
//System.out.println(theStructure.getMonitoring());
// > com16[n0(0 1)] com18[n1(5 4)] com20[n2(3 2)] com22[n3(7 6)]
// Shuffle around to stress bookkeeping
theStructure._moveNodeTo(2, theStructure.nodeCommunities[0]);
theStructure._moveNodeTo(0, theStructure.nodeCommunities[1]);
theStructure._moveNodeTo(1, theStructure.nodeCommunities[3]);
//System.out.println(theStructure.getMonitoring());
// > com16[n2(3 2)] com18[n0(0 1)] com22[n3(7 6) n1(5 4)]
// Zoom out again
theStructure._zoomOut();
//System.out.println(theStructure.getMonitoring());
// > com24[n0(3 2)] com26[n1(0 1)] com28[n2(7 6 5 4)]
// Test
// Compute description length
double descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
int node = 1;
StatisticalInferenceClustering.Community community = theStructure.nodeCommunities[0]; // Node 0's community
// Benchmark the delta
Double E = theStructure.graphWeightSum;
Double e_in = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
Double e_out = E - e_in;
Double B = Double.valueOf(theStructure.communities.size());
Double N = Double.valueOf(theStructure.graph.getNodeCount());
double descriptionLength_delta = sic.delta(node, community, theStructure, e_in, e_out, E, B, N);
// Actually move the node
theStructure._moveNodeTo(node, community);
// Compute description length again
double descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
// Delta should be (approximately) equal to the difference
assertEquals(descriptionLength_after - descriptionLength_before, descriptionLength_delta, 0.0001);
}
// The four next tests are networks from Tiago Peixoto, with a reference partition and description length.
@Test
public void testDescriptionLength_football() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "football.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
HashMap<Integer, StatisticalInferenceClustering.Community> knownCommunities = new HashMap<>();
NodeIterable nodesIterable = graph.getNodes();
for (Node node : nodesIterable) {
Integer targetCom = (Integer) node.getAttribute("key1");
int nodeIndex = theStructure.map.get(node);
StatisticalInferenceClustering.Community initCom = theStructure.nodeCommunities[nodeIndex];
if (knownCommunities.containsKey(targetCom)) {
theStructure._moveNodeTo(nodeIndex, knownCommunities.get(targetCom));
} else {
knownCommunities.put(targetCom, initCom);
}
}
double descriptionLength = sic.computeDescriptionLength(graph, theStructure);
assertEquals(1850.2102335828238, descriptionLength, 0.0001);
}
@Test
public void testDescriptionLength_moviegalaxies() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "moviegalaxies.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
HashMap<Integer, StatisticalInferenceClustering.Community> knownCommunities = new HashMap<>();
NodeIterable nodesIterable = graph.getNodes();
for (Node node : nodesIterable) {
Integer targetCom = (Integer) node.getAttribute("key1");
int nodeIndex = theStructure.map.get(node);
StatisticalInferenceClustering.Community initCom = theStructure.nodeCommunities[nodeIndex];
if (knownCommunities.containsKey(targetCom)) {
theStructure._moveNodeTo(nodeIndex, knownCommunities.get(targetCom));
} else {
knownCommunities.put(targetCom, initCom);
}
}
double descriptionLength = sic.computeDescriptionLength(graph, theStructure);
assertEquals(229.04187438186472, descriptionLength, 0.0001);
}
@Test
public void testDescriptionLength_5cliques() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "5-cliques.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
HashMap<Integer, StatisticalInferenceClustering.Community> knownCommunities = new HashMap<>();
NodeIterable nodesIterable = graph.getNodes();
for (Node node : nodesIterable) {
Integer targetCom = (Integer) node.getAttribute("key1");
int nodeIndex = theStructure.map.get(node);
StatisticalInferenceClustering.Community initCom = theStructure.nodeCommunities[nodeIndex];
if (knownCommunities.containsKey(targetCom)) {
theStructure._moveNodeTo(nodeIndex, knownCommunities.get(targetCom));
} else {
knownCommunities.put(targetCom, initCom);
}
}
double descriptionLength = sic.computeDescriptionLength(graph, theStructure);
assertEquals(150.10880360418344, descriptionLength, 0.0001);
}
@Test
public void testDescriptionLength_2cliques() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "two-cliques.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
HashMap<Integer, StatisticalInferenceClustering.Community> knownCommunities = new HashMap<>();
NodeIterable nodesIterable = graph.getNodes();
for (Node node : nodesIterable) {
Integer targetCom = (Integer) node.getAttribute("key1");
int nodeIndex = theStructure.map.get(node);
StatisticalInferenceClustering.Community initCom = theStructure.nodeCommunities[nodeIndex];
if (knownCommunities.containsKey(targetCom)) {
theStructure._moveNodeTo(nodeIndex, knownCommunities.get(targetCom));
} else {
knownCommunities.put(targetCom, initCom);
}
}
double descriptionLength = sic.computeDescriptionLength(graph, theStructure);
assertEquals(43.479327707987835, descriptionLength, 0.0001);
}
@Test
public void testMiscMetricsConsistentThroughZoomOut() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
StatisticalInferenceClustering.Community cA1 = theStructure.nodeCommunities[0];
StatisticalInferenceClustering.Community cA2 = theStructure.nodeCommunities[3];
StatisticalInferenceClustering.Community cB = theStructure.nodeCommunities[4];
theStructure._moveNodeTo(1, cA1);
theStructure._moveNodeTo(2, cA1);
theStructure._moveNodeTo(5, cB);
theStructure._moveNodeTo(6, cB);
theStructure._moveNodeTo(7, cB);
// Total number of edges (graph size)
double E_before = theStructure.graphWeightSum;
// Total number of edges from one community to the same one
double e_in_before = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
// Total number of communities
double B_before = Double.valueOf(theStructure.communities.size());
// Total number of nodes (not metanodes!!!)
double N_before = Double.valueOf(theStructure.graph.getNodeCount());
ArrayList<Double> e_r_before = new ArrayList<>();
ArrayList<Double> e_rr_before = new ArrayList<>();
ArrayList<Integer> n_r_before = new ArrayList<>();
for (StatisticalInferenceClustering.Community community : theStructure.communities) {
// Number of edges of community (with itself or another one)
double e_r = community.weightSum;
// Number of edges within community
double e_rr = community.internalWeightSum;
// Number of nodes in the community
int n_r = community.graphNodeCount;
e_r_before.add(e_r);
e_rr_before.add(e_rr);
n_r_before.add(n_r);
}
theStructure._zoomOut();
// Total number of edges (graph size)
double E_after = theStructure.graphWeightSum;
// Total number of edges from one community to the same one
double e_in_after = theStructure.communities.stream().mapToDouble(c -> c.internalWeightSum).sum();
// Total number of communities
double B_after = Double.valueOf(theStructure.communities.size());
// Total number of nodes (not metanodes!!!)
double N_after = Double.valueOf(theStructure.graph.getNodeCount());
ArrayList<Double> e_r_after = new ArrayList<>();
ArrayList<Double> e_rr_after = new ArrayList<>();
ArrayList<Integer> n_r_after = new ArrayList<>();
for (StatisticalInferenceClustering.Community community : theStructure.communities) {
// Number of edges of community (with itself or another one)
double e_r = community.weightSum;
// Number of edges within community
double e_rr = community.internalWeightSum;
// Number of nodes in the community
int n_r = community.graphNodeCount;
e_r_after.add(e_r);
e_rr_after.add(e_rr);
n_r_after.add(n_r);
}
assertEquals(E_before, E_after);
assertEquals(e_in_before, e_in_after);
assertEquals(B_before, B_after);
assertEquals(N_before, N_after);
assertEquals(e_r_before, e_r_after);
assertEquals(e_rr_before, e_rr_after);
assertEquals(n_r_before, n_r_after);
}
@Test
public void testDescriptionLengthConsistentThroughZoomOut_simple() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
StatisticalInferenceClustering.Community cA1 = theStructure.nodeCommunities[0];
StatisticalInferenceClustering.Community cA2 = theStructure.nodeCommunities[3];
StatisticalInferenceClustering.Community cB = theStructure.nodeCommunities[4];
theStructure._moveNodeTo(1, cA1);
theStructure._moveNodeTo(2, cA1);
theStructure._moveNodeTo(5, cB);
theStructure._moveNodeTo(6, cB);
theStructure._moveNodeTo(7, cB);
double descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
theStructure._zoomOut();
double descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
assertEquals(descriptionLength_before, descriptionLength_after, 0.00001);
}
@Test
public void testDescriptionLengthConsistentThroughZoomOut_complicated() {
UndirectedGraph graph = getCliquesBridgeGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
double descriptionLength_before;
double descriptionLength_after;
//System.out.println("\n# Initial");
//System.out.println(" Structure: "+theStructure.getMonitoring());
//System.out.println(" DL: "+sic.computeDescriptionLength(graph, theStructure));
// Move the nodes in categories
//System.out.println("\n# 1st round of group rearranging");
theStructure._moveNodeTo(1, theStructure.nodeCommunities[0]);
theStructure._moveNodeTo(3, theStructure.nodeCommunities[2]);
//System.out.println(" Structure: "+theStructure.getMonitoring());
descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
//System.out.println(" DL: "+descriptionLength_before);
// Zoom out
//System.out.println("\n# Zoom out");
theStructure._zoomOut();
//System.out.println(" Structure: "+theStructure.getMonitoring());
descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
//System.out.println(" DL: "+descriptionLength_after);
assertEquals(descriptionLength_before, descriptionLength_after, 0.00001);
// Move the nodes in categories
//System.out.println("\n# 2nd round of group rearranging");
theStructure._moveNodeTo(1, theStructure.nodeCommunities[2]);
//System.out.println(" Structure: "+theStructure.getMonitoring());
descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
//System.out.println(" DL: "+descriptionLength_before);
// Zoom out
//System.out.println("\n# Zoom out");
theStructure._zoomOut();
//System.out.println(" Structure: "+theStructure.getMonitoring());
descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
//System.out.println(" DL: "+descriptionLength_after);
assertEquals(descriptionLength_before, descriptionLength_after, 0.00001);
// Move the nodes in categories
//System.out.println("\n# 3rd round of group rearranging");
theStructure._moveNodeTo(2, theStructure.nodeCommunities[4]);
theStructure._moveNodeTo(3, theStructure.nodeCommunities[4]);
//System.out.println(" Structure: "+theStructure.getMonitoring());
descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
//System.out.println(" DL: "+descriptionLength_before);
// Zoom out
//System.out.println("\n# Zoom out");
theStructure._zoomOut();
//System.out.println(" Structure: "+theStructure.getMonitoring());
descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
//System.out.println(" DL: "+descriptionLength_after);
assertEquals(descriptionLength_before, descriptionLength_after, 0.00001);
}
/*
// This test is not unitary enough, it may randomly fail by design. Useful for debugging though.
@Test
public void testMinimizationHeuristic_football() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "football.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
sic.execute(graph);
double descriptionLength = sic.getDescriptionLength();
double targetDescLength = 1850.2102335828238;
double errorMargin = 0.1;
assertEquals(targetDescLength, descriptionLength, errorMargin * targetDescLength);
}
*/
@Test
public void testMinimizationHeuristic_5cliques() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "5-cliques.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
sic.execute(graph);
double descriptionLength = sic.getDescriptionLength();
double targetDescLength = 150.10880360418344;
double errorMargin = 0.01;
assertEquals(targetDescLength, descriptionLength, errorMargin * targetDescLength);
}
@Test
public void testMinimizationHeuristic_moviegalaxies() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "moviegalaxies.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
sic.execute(graph);
double descriptionLength = sic.getDescriptionLength();
double targetDescLength = 229.04187438186472;
double errorMargin = 0.1;
assertEquals(targetDescLength, descriptionLength, errorMargin * targetDescLength);
}
@Test
public void testDescriptionLengthZoomOut_football() {
GraphModel graphModel = GraphImporter.importGraph(DummyTest.class, "football.graphml");
UndirectedGraph graph = graphModel.getUndirectedGraph();
StatisticalInferenceClustering sic = new StatisticalInferenceClustering();
StatisticalInferenceClustering.CommunityStructure theStructure = sic.new CommunityStructure(graph);
// We reproduce a given setting
StatisticalInferenceClustering.Community c0 = theStructure.nodeCommunities[74];
theStructure._moveNodeTo(102, c0);
theStructure._moveNodeTo(107, c0);
theStructure._moveNodeTo(49, c0);
theStructure._moveNodeTo(84, c0);
theStructure._moveNodeTo(82, c0);
theStructure._moveNodeTo(77, c0);
theStructure._moveNodeTo(72, c0);
theStructure._moveNodeTo(2, c0);
theStructure._moveNodeTo(98, c0);
theStructure._moveNodeTo(10, c0);
StatisticalInferenceClustering.Community c1 = theStructure.nodeCommunities[30];
theStructure._moveNodeTo(19, c1);
theStructure._moveNodeTo(60, c1);
theStructure._moveNodeTo(71, c1);
theStructure._moveNodeTo(18, c1);
theStructure._moveNodeTo(99, c1);
theStructure._moveNodeTo(35, c1);
theStructure._moveNodeTo(79, c1);
theStructure._moveNodeTo(38, c1);
theStructure._moveNodeTo(85, c1);
theStructure._moveNodeTo(28, c1);
theStructure._moveNodeTo(55, c1);
theStructure._moveNodeTo(6, c1);
theStructure._moveNodeTo(31, c1);
theStructure._moveNodeTo(54, c1);
StatisticalInferenceClustering.Community c2 = theStructure.nodeCommunities[20];
theStructure._moveNodeTo(36, c2);
theStructure._moveNodeTo(75, c2);
theStructure._moveNodeTo(48, c2);
theStructure._moveNodeTo(92, c2);
theStructure._moveNodeTo(58, c2);
theStructure._moveNodeTo(59, c2);
theStructure._moveNodeTo(113, c2);
StatisticalInferenceClustering.Community c3 = theStructure.nodeCommunities[68];
theStructure._moveNodeTo(8, c3);
theStructure._moveNodeTo(22, c3);
theStructure._moveNodeTo(78, c3);
theStructure._moveNodeTo(51, c3);
theStructure._moveNodeTo(111, c3);
theStructure._moveNodeTo(40, c3);
theStructure._moveNodeTo(7, c3);
theStructure._moveNodeTo(21, c3);
theStructure._moveNodeTo(108, c3);
StatisticalInferenceClustering.Community c4 = theStructure.nodeCommunities[70];
theStructure._moveNodeTo(87, c4);
theStructure._moveNodeTo(64, c4);
theStructure._moveNodeTo(63, c4);
theStructure._moveNodeTo(97, c4);
theStructure._moveNodeTo(24, c4);
theStructure._moveNodeTo(66, c4);
theStructure._moveNodeTo(56, c4);
theStructure._moveNodeTo(65, c4);
theStructure._moveNodeTo(27, c4);
theStructure._moveNodeTo(95, c4);
theStructure._moveNodeTo(76, c4);
theStructure._moveNodeTo(96, c4);
theStructure._moveNodeTo(57, c4);
theStructure._moveNodeTo(91, c4);
theStructure._moveNodeTo(86, c4);
theStructure._moveNodeTo(53, c4);
theStructure._moveNodeTo(17, c4);
theStructure._moveNodeTo(12, c4);
theStructure._moveNodeTo(44, c4);
theStructure._moveNodeTo(112, c4);
StatisticalInferenceClustering.Community c5 = theStructure.nodeCommunities[103];
theStructure._moveNodeTo(109, c5);
theStructure._moveNodeTo(37, c5);
theStructure._moveNodeTo(89, c5);
theStructure._moveNodeTo(33, c5);
theStructure._moveNodeTo(105, c5);
theStructure._moveNodeTo(25, c5);
theStructure._moveNodeTo(106, c5);
theStructure._moveNodeTo(62, c5);
theStructure._moveNodeTo(45, c5);
theStructure._moveNodeTo(1, c5);
theStructure._moveNodeTo(101, c5);
StatisticalInferenceClustering.Community c6 = theStructure.nodeCommunities[23];
theStructure._moveNodeTo(0, c6);
theStructure._moveNodeTo(93, c6);
theStructure._moveNodeTo(9, c6);
theStructure._moveNodeTo(16, c6);
theStructure._moveNodeTo(81, c6);
theStructure._moveNodeTo(41, c6);
theStructure._moveNodeTo(50, c6);
theStructure._moveNodeTo(90, c6);
theStructure._moveNodeTo(5, c6);
theStructure._moveNodeTo(4, c6);
StatisticalInferenceClustering.Community c7 = theStructure.nodeCommunities[100];
theStructure._moveNodeTo(39, c7);
theStructure._moveNodeTo(43, c7);
theStructure._moveNodeTo(14, c7);
theStructure._moveNodeTo(32, c7);
theStructure._moveNodeTo(47, c7);
theStructure._moveNodeTo(42, c7);
theStructure._moveNodeTo(34, c7);
theStructure._moveNodeTo(94, c7);
theStructure._moveNodeTo(13, c7);
theStructure._moveNodeTo(15, c7);
theStructure._moveNodeTo(26, c7);
theStructure._moveNodeTo(61, c7);
theStructure._moveNodeTo(29, c7);
theStructure._moveNodeTo(80, c7);
StatisticalInferenceClustering.Community c8 = theStructure.nodeCommunities[67];
theStructure._moveNodeTo(88, c8);
theStructure._moveNodeTo(69, c8);
theStructure._moveNodeTo(83, c8);
theStructure._moveNodeTo(73, c8);
theStructure._moveNodeTo(114, c8);
theStructure._moveNodeTo(104, c8);
theStructure._moveNodeTo(11, c8);
theStructure._moveNodeTo(52, c8);
theStructure._moveNodeTo(3, c8);
theStructure._moveNodeTo(46, c8);
theStructure._moveNodeTo(110, c8);
double descriptionLength_before = sic.computeDescriptionLength(graph, theStructure);
theStructure._zoomOut();
double descriptionLength_after = sic.computeDescriptionLength(graph, theStructure);
assertEquals(descriptionLength_before, descriptionLength_after, 0.00001);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<!-- property keys -->
<key id="key0" for="graph" attr.name="dl" attr.type="float" />
<key id="key1" for="node" attr.name="partition" attr.type="int" />
<graph id="G" edgedefault="undirected" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
<!-- graph properties -->
<data key="key0">150.10880360418344</data>
<!-- vertices -->
<node id="n0">
<data key="key1">0</data>
</node>
<node id="n1">
<data key="key1">0</data>
</node>
<node id="n2">
<data key="key1">0</data>
</node>
<node id="n3">
<data key="key1">0</data>
</node>
<node id="n4">
<data key="key1">0</data>
</node>
<node id="n5">
<data key="key1">1</data>
</node>
<node id="n6">
<data key="key1">1</data>
</node>
<node id="n7">
<data key="key1">1</data>
</node>
<node id="n8">
<data key="key1">1</data>
</node>
<node id="n9">
<data key="key1">1</data>
</node>
<node id="n10">
<data key="key1">2</data>
</node>
<node id="n11">
<data key="key1">2</data>
</node>
<node id="n12">
<data key="key1">2</data>
</node>
<node id="n13">
<data key="key1">2</data>
</node>
<node id="n14">
<data key="key1">2</data>
</node>
<node id="n15">
<data key="key1">3</data>
</node>
<node id="n16">
<data key="key1">3</data>
</node>
<node id="n17">
<data key="key1">3</data>
</node>
<node id="n18">
<data key="key1">3</data>
</node>
<node id="n19">
<data key="key1">3</data>
</node>
<node id="n20">
<data key="key1">4</data>
</node>
<node id="n21">
<data key="key1">4</data>
</node>
<node id="n22">
<data key="key1">4</data>
</node>
<node id="n23">
<data key="key1">4</data>
</node>
<node id="n24">
<data key="key1">4</data>
</node>
<!-- edges -->
<edge id="e0" source="n0" target="n1">
</edge>
<edge id="e1" source="n0" target="n2">
</edge>
<edge id="e2" source="n0" target="n3">
</edge>
<edge id="e3" source="n0" target="n4">
</edge>
<edge id="e4" source="n0" target="n5">
</edge>
<edge id="e5" source="n1" target="n2">
</edge>
<edge id="e6" source="n1" target="n3">
</edge>
<edge id="e7" source="n1" target="n4">
</edge>
<edge id="e8" source="n2" target="n3">
</edge>
<edge id="e9" source="n2" target="n4">
</edge>
<edge id="e10" source="n3" target="n4">
</edge>
<edge id="e11" source="n5" target="n6">
</edge>
<edge id="e12" source="n5" target="n7">
</edge>
<edge id="e13" source="n5" target="n8">
</edge>
<edge id="e14" source="n5" target="n9">
</edge>
<edge id="e15" source="n5" target="n10">
</edge>
<edge id="e16" source="n6" target="n7">
</edge>
<edge id="e17" source="n6" target="n8">
</edge>
<edge id="e18" source="n6" target="n9">
</edge>
<edge id="e19" source="n7" target="n8">
</edge>
<edge id="e20" source="n7" target="n9">
</edge>
<edge id="e21" source="n8" target="n9">
</edge>
<edge id="e22" source="n10" target="n11">
</edge>
<edge id="e23" source="n10" target="n12">
</edge>
<edge id="e24" source="n10" target="n13">
</edge>
<edge id="e25" source="n10" target="n14">
</edge>
<edge id="e26" source="n10" target="n15">
</edge>
<edge id="e27" source="n11" target="n12">
</edge>
<edge id="e28" source="n11" target="n13">
</edge>
<edge id="e29" source="n11" target="n14">
</edge>
<edge id="e30" source="n12" target="n13">
</edge>
<edge id="e31" source="n12" target="n14">
</edge>
<edge id="e32" source="n13" target="n14">
</edge>
<edge id="e33" source="n15" target="n16">
</edge>
<edge id="e34" source="n15" target="n17">
</edge>
<edge id="e35" source="n15" target="n18">
</edge>
<edge id="e36" source="n15" target="n19">
</edge>
<edge id="e37" source="n15" target="n20">
</edge>
<edge id="e38" source="n16" target="n17">
</edge>
<edge id="e39" source="n16" target="n18">
</edge>
<edge id="e40" source="n16" target="n19">
</edge>
<edge id="e41" source="n17" target="n18">
</edge>
<edge id="e42" source="n17" target="n19">
</edge>
<edge id="e43" source="n18" target="n19">
</edge>
<edge id="e44" source="n20" target="n21">
</edge>
<edge id="e45" source="n20" target="n22">
</edge>
<edge id="e46" source="n20" target="n23">
</edge>
<edge id="e47" source="n20" target="n24">
</edge>
<edge id="e48" source="n21" target="n22">
</edge>
<edge id="e49" source="n21" target="n23">
</edge>
<edge id="e50" source="n21" target="n24">
</edge>
<edge id="e51" source="n22" target="n23">
</edge>
<edge id="e52" source="n22" target="n24">
</edge>
<edge id="e53" source="n23" target="n24">
</edge>
</graph>
</graphml>
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<!-- property keys -->
<key id="key0" for="graph" attr.name="dl" attr.type="float" />
<key id="key1" for="node" attr.name="partition" attr.type="int" />
<graph id="G" edgedefault="undirected" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
<!-- graph properties -->
<data key="key0">1850.2102335828238</data>
<!-- vertices -->
<node id="n0">
<data key="key1">9</data>
</node>
<node id="n1">
<data key="key1">6</data>
</node>
<node id="n2">
<data key="key1">3</data>
</node>
<node id="n3">
<data key="key1">1</data>
</node>
<node id="n4">
<data key="key1">9</data>
</node>
<node id="n5">
<data key="key1">1</data>
</node>
<node id="n6">
<data key="key1">3</data>
</node>
<node id="n7">
<data key="key1">4</data>
</node>
<node id="n8">
<data key="key1">4</data>
</node>
<node id="n9">
<data key="key1">9</data>
</node>
<node id="n10">
<data key="key1">1</data>
</node>
<node id="n11">
<data key="key1">10</data>
</node>
<node id="n12">
<data key="key1">0</data>
</node>
<node id="n13">
<data key="key1">3</data>
</node>
<node id="n14">
<data key="key1">0</data>
</node>
<node id="n15">
<data key="key1">3</data>
</node>
<node id="n16">
<data key="key1">9</data>
</node>
<node id="n17">
<data key="key1">2</data>
</node>
<node id="n18">
<data key="key1">0</data>
</node>
<node id="n19">
<data key="key1">5</data>
</node>
<node id="n20">
<data key="key1">2</data>
</node>
<node id="n21">
<data key="key1">4</data>
</node>
<node id="n22">
<data key="key1">4</data>
</node>
<node id="n23">
<data key="key1">9</data>
</node>
<node id="n24">
<data key="key1">10</data>
</node>
<node id="n25">
<data key="key1">6</data>
</node>
<node id="n26">
<data key="key1">0</data>
</node>
<node id="n27">
<data key="key1">2</data>
</node>
<node id="n28">
<data key="key1">10</data>
</node>
<node id="n29">
<data key="key1">5</data>
</node>
<node id="n30">
<data key="key1">5</data>
</node>
<node id="n31">
<data key="key1">0</data>
</node>
<node id="n32">
<data key="key1">3</data>
</node>
<node id="n33">
<data key="key1">6</data>
</node>
<node id="n34">
<data key="key1">0</data>
</node>
<node id="n35">
<data key="key1">5</data>
</node>
<node id="n36">
<data key="key1">11</data>
</node>
<node id="n37">
<data key="key1">6</data>
</node>
<node id="n38">
<data key="key1">0</data>
</node>
<node id="n39">
<data key="key1">3</data>
</node>
<node id="n40">
<data key="key1">1</data>
</node>
<node id="n41">
<data key="key1">9</data>
</node>
<node id="n42">
<data key="key1">0</data>
</node>
<node id="n43">
<data key="key1">0</data>
</node>
<node id="n44">
<data key="key1">7</data>
</node>
<node id="n45">
<data key="key1">6</data>
</node>
<node id="n46">
<data key="key1">8</data>
</node>
<node id="n47">
<data key="key1">3</data>
</node>
<node id="n48">
<data key="key1">7</data>
</node>
<node id="n49">
<data key="key1">8</data>
</node>
<node id="n50">
<data key="key1">10</data>
</node>
<node id="n51">
<data key="key1">4</data>
</node>
<node id="n52">
<data key="key1">1</data>
</node>
<node id="n53">
<data key="key1">8</data>
</node>
<node id="n54">
<data key="key1">0</data>
</node>
<node id="n55">
<data key="key1">5</data>
</node>
<node id="n56">
<data key="key1">2</data>
</node>
<node id="n57">
<data key="key1">7</data>
</node>
<node id="n58">
<data key="key1">11</data>
</node>
<node id="n59">
<data key="key1">11</data>
</node>
<node id="n60">
<data key="key1">3</data>
</node>
<node id="n61">
<data key="key1">0</data>
</node>
<node id="n62">
<data key="key1">2</data>
</node>
<node id="n63">
<data key="key1">11</data>
</node>
<node id="n64">
<data key="key1">3</data>
</node>
<node id="n65">
<data key="key1">2</data>
</node>
<node id="n66">
<data key="key1">7</data>
</node>
<node id="n67">
<data key="key1">8</data>
</node>
<node id="n68">
<data key="key1">4</data>
</node>
<node id="n69">
<data key="key1">10</data>
</node>
<node id="n70">
<data key="key1">2</data>
</node>
<node id="n71">
<data key="key1">0</data>
</node>
<node id="n72">
<data key="key1">1</data>
</node>
<node id="n73">
<data key="key1">8</data>
</node>
<node id="n74">
<data key="key1">1</data>
</node>
<node id="n75">
<data key="key1">7</data>
</node>
<node id="n76">
<data key="key1">2</data>
</node>
<node id="n77">
<data key="key1">4</data>
</node>
<node id="n78">
<data key="key1">4</data>
</node>
<node id="n79">
<data key="key1">5</data>
</node>
<node id="n80">
<data key="key1">5</data>
</node>
<node id="n81">
<data key="key1">1</data>
</node>
<node id="n82">
<data key="key1">5</data>
</node>
<node id="n83">
<data key="key1">8</data>
</node>
<node id="n84">
<data key="key1">1</data>
</node>
<node id="n85">
<data key="key1">0</data>
</node>
<node id="n86">
<data key="key1">7</data>
</node>
<node id="n87">
<data key="key1">2</data>
</node>
<node id="n88">
<data key="key1">8</data>
</node>
<node id="n89">
<data key="key1">6</data>
</node>
<node id="n90">
<data key="key1">10</data>
</node>
<node id="n91">
<data key="key1">7</data>
</node>
<node id="n92">
<data key="key1">7</data>
</node>
<node id="n93">
<data key="key1">9</data>
</node>
<node id="n94">
<data key="key1">5</data>
</node>
<node id="n95">
<data key="key1">2</data>
</node>
<node id="n96">
<data key="key1">2</data>
</node>
<node id="n97">
<data key="key1">11</data>
</node>
<node id="n98">
<data key="key1">1</data>
</node>
<node id="n99">
<data key="key1">0</data>
</node>
<node id="n100">
<data key="key1">3</data>
</node>
<node id="n101">
<data key="key1">5</data>
</node>
<node id="n102">
<data key="key1">1</data>
</node>
<node id="n103">
<data key="key1">6</data>
</node>
<node id="n104">
<data key="key1">9</data>
</node>
<node id="n105">
<data key="key1">6</data>
</node>
<node id="n106">
<data key="key1">3</data>
</node>
<node id="n107">
<data key="key1">1</data>
</node>
<node id="n108">
<data key="key1">4</data>
</node>
<node id="n109">
<data key="key1">6</data>
</node>
<node id="n110">
<data key="key1">8</data>
</node>
<node id="n111">
<data key="key1">4</data>
</node>
<node id="n112">
<data key="key1">7</data>
</node>
<node id="n113">
<data key="key1">2</data>
</node>
<node id="n114">
<data key="key1">8</data>
</node>
<!-- edges -->
<edge id="e0" source="n1" target="n0">
</edge>
<edge id="e1" source="n3" target="n2">
</edge>
<edge id="e2" source="n4" target="n0">
</edge>
<edge id="e3" source="n5" target="n4">
</edge>
<edge id="e4" source="n5" target="n3">
</edge>
<edge id="e5" source="n6" target="n2">
</edge>
<edge id="e6" source="n7" target="n6">
</edge>
<edge id="e7" source="n8" target="n7">
</edge>
<edge id="e8" source="n9" target="n8">
</edge>
<edge id="e9" source="n9" target="n0">
</edge>
<edge id="e10" source="n9" target="n4">
</edge>
<edge id="e11" source="n10" target="n5">
</edge>
<edge id="e12" source="n11" target="n10">
</edge>
<edge id="e13" source="n11" target="n5">
</edge>
<edge id="e14" source="n11" target="n3">
</edge>
<edge id="e15" source="n13" target="n12">
</edge>
<edge id="e16" source="n13" target="n2">
</edge>
<edge id="e17" source="n14" target="n2">
</edge>
<edge id="e18" source="n14" target="n12">
</edge>
<edge id="e19" source="n15" target="n14">
</edge>
<edge id="e20" source="n15" target="n13">
</edge>
<edge id="e21" source="n15" target="n2">
</edge>
<edge id="e22" source="n16" target="n4">
</edge>
<edge id="e23" source="n16" target="n9">
</edge>
<edge id="e24" source="n16" target="n0">
</edge>
<edge id="e25" source="n17" target="n16">
</edge>
<edge id="e26" source="n17" target="n12">
</edge>
<edge id="e27" source="n18" target="n12">
</edge>
<edge id="e28" source="n19" target="n18">
</edge>
<edge id="e29" source="n20" target="n17">
</edge>
<edge id="e30" source="n21" target="n20">
</edge>
<edge id="e31" source="n21" target="n8">
</edge>
<edge id="e32" source="n21" target="n7">
</edge>
<edge id="e33" source="n22" target="n9">
</edge>
<edge id="e34" source="n22" target="n7">
</edge>
<edge id="e35" source="n22" target="n21">
</edge>
<edge id="e36" source="n22" target="n8">
</edge>
<edge id="e37" source="n23" target="n22">
</edge>
<edge id="e38" source="n23" target="n9">
</edge>
<edge id="e39" source="n23" target="n4">
</edge>
<edge id="e40" source="n23" target="n16">
</edge>
<edge id="e41" source="n23" target="n0">
</edge>
<edge id="e42" source="n24" target="n11">
</edge>
<edge id="e43" source="n25" target="n24">
</edge>
<edge id="e44" source="n25" target="n1">
</edge>
<edge id="e45" source="n26" target="n3">
</edge>
<edge id="e46" source="n26" target="n12">
</edge>
<edge id="e47" source="n26" target="n14">
</edge>
<edge id="e48" source="n27" target="n26">
</edge>
<edge id="e49" source="n27" target="n17">
</edge>
<edge id="e50" source="n27" target="n1">
</edge>
<edge id="e51" source="n28" target="n4">
</edge>
<edge id="e52" source="n28" target="n11">
</edge>
<edge id="e53" source="n28" target="n24">
</edge>
<edge id="e54" source="n29" target="n19">
</edge>
<edge id="e55" source="n30" target="n29">
</edge>
<edge id="e56" source="n30" target="n19">
</edge>
<edge id="e57" source="n31" target="n18">
</edge>
<edge id="e58" source="n32" target="n31">
</edge>
<edge id="e59" source="n32" target="n21">
</edge>
<edge id="e60" source="n32" target="n15">
</edge>
<edge id="e61" source="n32" target="n13">
</edge>
<edge id="e62" source="n32" target="n6">
</edge>
<edge id="e63" source="n33" target="n0">
</edge>
<edge id="e64" source="n33" target="n1">
</edge>
<edge id="e65" source="n33" target="n25">
</edge>
<edge id="e66" source="n33" target="n19">
</edge>
<edge id="e67" source="n34" target="n31">
</edge>
<edge id="e68" source="n34" target="n26">
</edge>
<edge id="e69" source="n34" target="n12">
</edge>
<edge id="e70" source="n34" target="n18">
</edge>
<edge id="e71" source="n35" target="n34">
</edge>
<edge id="e72" source="n35" target="n0">
</edge>
<edge id="e73" source="n35" target="n29">
</edge>
<edge id="e74" source="n35" target="n19">
</edge>
<edge id="e75" source="n35" target="n30">
</edge>
<edge id="e76" source="n36" target="n18">
</edge>
<edge id="e77" source="n36" target="n12">
</edge>
<edge id="e78" source="n36" target="n20">
</edge>
<edge id="e79" source="n36" target="n19">
</edge>
<edge id="e80" source="n37" target="n36">
</edge>
<edge id="e81" source="n37" target="n1">
</edge>
<edge id="e82" source="n37" target="n25">
</edge>
<edge id="e83" source="n37" target="n33">
</edge>
<edge id="e84" source="n38" target="n18">
</edge>
<edge id="e85" source="n38" target="n16">
</edge>
<edge id="e86" source="n38" target="n28">
</edge>
<edge id="e87" source="n38" target="n26">
</edge>
<edge id="e88" source="n38" target="n14">
</edge>
<edge id="e89" source="n38" target="n12">
</edge>
<edge id="e90" source="n39" target="n38">
</edge>
<edge id="e91" source="n39" target="n6">
</edge>
<edge id="e92" source="n39" target="n32">
</edge>
<edge id="e93" source="n39" target="n13">
</edge>
<edge id="e94" source="n39" target="n15">
</edge>
<edge id="e95" source="n40" target="n7">
</edge>
<edge id="e96" source="n40" target="n3">
</edge>
<edge id="e97" source="n41" target="n40">
</edge>
<edge id="e98" source="n41" target="n8">
</edge>
<edge id="e99" source="n41" target="n4">
</edge>
<edge id="e100" source="n41" target="n23">
</edge>
<edge id="e101" source="n41" target="n9">
</edge>
<edge id="e102" source="n41" target="n0">
</edge>
<edge id="e103" source="n41" target="n16">
</edge>
<edge id="e104" source="n42" target="n34">
</edge>
<edge id="e105" source="n42" target="n29">
</edge>
<edge id="e106" source="n42" target="n18">
</edge>
<edge id="e107" source="n42" target="n26">
</edge>
<edge id="e108" source="n43" target="n42">
</edge>
<edge id="e109" source="n43" target="n36">
</edge>
<edge id="e110" source="n43" target="n26">
</edge>
<edge id="e111" source="n43" target="n31">
</edge>
<edge id="e112" source="n43" target="n38">
</edge>
<edge id="e113" source="n43" target="n12">
</edge>
<edge id="e114" source="n43" target="n14">
</edge>
<edge id="e115" source="n44" target="n19">
</edge>
<edge id="e116" source="n44" target="n35">
</edge>
<edge id="e117" source="n44" target="n30">
</edge>
<edge id="e118" source="n45" target="n44">
</edge>
<edge id="e119" source="n45" target="n13">
</edge>
<edge id="e120" source="n45" target="n33">
</edge>
<edge id="e121" source="n45" target="n1">
</edge>
<edge id="e122" source="n45" target="n37">
</edge>
<edge id="e123" source="n45" target="n25">
</edge>
<edge id="e124" source="n46" target="n21">
</edge>
<edge id="e125" source="n47" target="n46">
</edge>
<edge id="e126" source="n47" target="n22">
</edge>
<edge id="e127" source="n47" target="n6">
</edge>
<edge id="e128" source="n47" target="n15">
</edge>
<edge id="e129" source="n47" target="n2">
</edge>
<edge id="e130" source="n47" target="n39">
</edge>
<edge id="e131" source="n47" target="n32">
</edge>
<edge id="e132" source="n48" target="n44">
</edge>
<edge id="e133" source="n49" target="n48">
</edge>
<edge id="e134" source="n49" target="n32">
</edge>
<edge id="e135" source="n49" target="n46">
</edge>
<edge id="e136" source="n50" target="n30">
</edge>
<edge id="e137" source="n50" target="n24">
</edge>
<edge id="e138" source="n50" target="n11">
</edge>
<edge id="e139" source="n50" target="n28">
</edge>
<edge id="e140" source="n51" target="n50">
</edge>
<edge id="e141" source="n51" target="n40">
</edge>
<edge id="e142" source="n51" target="n8">
</edge>
<edge id="e143" source="n51" target="n22">
</edge>
<edge id="e144" source="n51" target="n21">
</edge>
<edge id="e145" source="n52" target="n3">
</edge>
<edge id="e146" source="n52" target="n40">
</edge>
<edge id="e147" source="n52" target="n5">
</edge>
<edge id="e148" source="n53" target="n52">
</edge>
<edge id="e149" source="n53" target="n25">
</edge>
<edge id="e150" source="n53" target="n48">
</edge>
<edge id="e151" source="n53" target="n49">
</edge>
<edge id="e152" source="n53" target="n46">
</edge>
<edge id="e153" source="n54" target="n39">
</edge>
<edge id="e154" source="n54" target="n31">
</edge>
<edge id="e155" source="n54" target="n38">
</edge>
<edge id="e156" source="n54" target="n14">
</edge>
<edge id="e157" source="n54" target="n34">
</edge>
<edge id="e158" source="n54" target="n18">
</edge>
<edge id="e159" source="n55" target="n54">
</edge>
<edge id="e160" source="n55" target="n31">
</edge>
<edge id="e161" source="n55" target="n6">
</edge>
<edge id="e162" source="n55" target="n35">
</edge>
<edge id="e163" source="n55" target="n29">
</edge>
<edge id="e164" source="n55" target="n19">
</edge>
<edge id="e165" source="n55" target="n30">
</edge>
<edge id="e166" source="n56" target="n27">
</edge>
<edge id="e167" source="n57" target="n56">
</edge>
<edge id="e168" source="n57" target="n1">
</edge>
<edge id="e169" source="n57" target="n42">
</edge>
<edge id="e170" source="n57" target="n44">
</edge>
<edge id="e171" source="n57" target="n48">
</edge>
<edge id="e172" source="n58" target="n3">
</edge>
<edge id="e173" source="n58" target="n6">
</edge>
<edge id="e174" source="n58" target="n17">
</edge>
<edge id="e175" source="n58" target="n36">
</edge>
<edge id="e176" source="n59" target="n36">
</edge>
<edge id="e177" source="n59" target="n58">
</edge>
<edge id="e178" source="n60" target="n59">
</edge>
<edge id="e179" source="n60" target="n10">
</edge>
<edge id="e180" source="n60" target="n39">
</edge>
<edge id="e181" source="n60" target="n6">
</edge>
<edge id="e182" source="n60" target="n47">
</edge>
<edge id="e183" source="n60" target="n13">
</edge>
<edge id="e184" source="n60" target="n15">
</edge>
<edge id="e185" source="n60" target="n2">
</edge>
<edge id="e186" source="n61" target="n43">
</edge>
<edge id="e187" source="n61" target="n47">
</edge>
<edge id="e188" source="n61" target="n54">
</edge>
<edge id="e189" source="n61" target="n18">
</edge>
<edge id="e190" source="n61" target="n26">
</edge>
<edge id="e191" source="n61" target="n31">
</edge>
<edge id="e192" source="n61" target="n34">
</edge>
<edge id="e193" source="n62" target="n61">
</edge>
<edge id="e194" source="n62" target="n20">
</edge>
<edge id="e195" source="n62" target="n45">
</edge>
<edge id="e196" source="n62" target="n17">
</edge>
<edge id="e197" source="n62" target="n27">
</edge>
<edge id="e198" source="n62" target="n56">
</edge>
<edge id="e199" source="n63" target="n27">
</edge>
<edge id="e200" source="n63" target="n58">
</edge>
<edge id="e201" source="n63" target="n59">
</edge>
<edge id="e202" source="n63" target="n42">
</edge>
<edge id="e203" source="n64" target="n63">
</edge>
<edge id="e204" source="n64" target="n9">
</edge>
<edge id="e205" source="n64" target="n32">
</edge>
<edge id="e206" source="n64" target="n60">
</edge>
<edge id="e207" source="n64" target="n2">
</edge>
<edge id="e208" source="n64" target="n6">
</edge>
<edge id="e209" source="n64" target="n47">
</edge>
<edge id="e210" source="n64" target="n13">
</edge>
<edge id="e211" source="n65" target="n0">
</edge>
<edge id="e212" source="n65" target="n27">
</edge>
<edge id="e213" source="n65" target="n17">
</edge>
<edge id="e214" source="n65" target="n63">
</edge>
<edge id="e215" source="n65" target="n56">
</edge>
<edge id="e216" source="n65" target="n20">
</edge>
<edge id="e217" source="n66" target="n65">
</edge>
<edge id="e218" source="n66" target="n59">
</edge>
<edge id="e219" source="n66" target="n24">
</edge>
<edge id="e220" source="n66" target="n44">
</edge>
<edge id="e221" source="n66" target="n48">
</edge>
<edge id="e222" source="n67" target="n16">
</edge>
<edge id="e223" source="n67" target="n41">
</edge>
<edge id="e224" source="n67" target="n46">
</edge>
<edge id="e225" source="n67" target="n53">
</edge>
<edge id="e226" source="n67" target="n49">
</edge>
<edge id="e227" source="n68" target="n67">
</edge>
<edge id="e228" source="n68" target="n15">
</edge>
<edge id="e229" source="n68" target="n50">
</edge>
<edge id="e230" source="n68" target="n21">
</edge>
<edge id="e231" source="n68" target="n51">
</edge>
<edge id="e232" source="n68" target="n7">
</edge>
<edge id="e233" source="n68" target="n22">
</edge>
<edge id="e234" source="n68" target="n8">
</edge>
<edge id="e235" source="n69" target="n4">
</edge>
<edge id="e236" source="n69" target="n24">
</edge>
<edge id="e237" source="n69" target="n28">
</edge>
<edge id="e238" source="n69" target="n50">
</edge>
<edge id="e239" source="n69" target="n11">
</edge>
<edge id="e240" source="n70" target="n69">
</edge>
<edge id="e241" source="n70" target="n43">
</edge>
<edge id="e242" source="n70" target="n65">
</edge>
<edge id="e243" source="n70" target="n20">
</edge>
<edge id="e244" source="n70" target="n56">
</edge>
<edge id="e245" source="n70" target="n62">
</edge>
<edge id="e246" source="n70" target="n27">
</edge>
<edge id="e247" source="n71" target="n60">
</edge>
<edge id="e248" source="n71" target="n18">
</edge>
<edge id="e249" source="n71" target="n14">
</edge>
<edge id="e250" source="n71" target="n34">
</edge>
<edge id="e251" source="n71" target="n54">
</edge>
<edge id="e252" source="n71" target="n38">
</edge>
<edge id="e253" source="n71" target="n61">
</edge>
<edge id="e254" source="n71" target="n31">
</edge>
<edge id="e255" source="n72" target="n71">
</edge>
<edge id="e256" source="n72" target="n2">
</edge>
<edge id="e257" source="n72" target="n10">
</edge>
<edge id="e258" source="n72" target="n3">
</edge>
<edge id="e259" source="n72" target="n40">
</edge>
<edge id="e260" source="n72" target="n52">
</edge>
<edge id="e261" source="n73" target="n7">
</edge>
<edge id="e262" source="n73" target="n49">
</edge>
<edge id="e263" source="n73" target="n53">
</edge>
<edge id="e264" source="n73" target="n67">
</edge>
<edge id="e265" source="n73" target="n46">
</edge>
<edge id="e266" source="n74" target="n73">
</edge>
<edge id="e267" source="n74" target="n2">
</edge>
<edge id="e268" source="n74" target="n72">
</edge>
<edge id="e269" source="n74" target="n5">
</edge>
<edge id="e270" source="n74" target="n10">
</edge>
<edge id="e271" source="n74" target="n52">
</edge>
<edge id="e272" source="n74" target="n3">
</edge>
<edge id="e273" source="n74" target="n40">
</edge>
<edge id="e274" source="n75" target="n20">
</edge>
<edge id="e275" source="n75" target="n66">
</edge>
<edge id="e276" source="n75" target="n48">
</edge>
<edge id="e277" source="n75" target="n57">
</edge>
<edge id="e278" source="n75" target="n44">
</edge>
<edge id="e279" source="n76" target="n75">
</edge>
<edge id="e280" source="n76" target="n27">
</edge>
<edge id="e281" source="n76" target="n59">
</edge>
<edge id="e282" source="n76" target="n20">
</edge>
<edge id="e283" source="n76" target="n70">
</edge>
<edge id="e284" source="n76" target="n66">
</edge>
<edge id="e285" source="n76" target="n56">
</edge>
<edge id="e286" source="n76" target="n62">
</edge>
<edge id="e287" source="n77" target="n73">
</edge>
<edge id="e288" source="n77" target="n22">
</edge>
<edge id="e289" source="n77" target="n7">
</edge>
<edge id="e290" source="n77" target="n51">
</edge>
<edge id="e291" source="n77" target="n21">
</edge>
<edge id="e292" source="n77" target="n8">
</edge>
<edge id="e293" source="n78" target="n77">
</edge>
<edge id="e294" source="n78" target="n23">
</edge>
<edge id="e295" source="n78" target="n50">
</edge>
<edge id="e296" source="n78" target="n28">
</edge>
<edge id="e297" source="n78" target="n22">
</edge>
<edge id="e298" source="n78" target="n8">
</edge>
<edge id="e299" source="n78" target="n68">
</edge>
<edge id="e300" source="n78" target="n7">
</edge>
<edge id="e301" source="n78" target="n51">
</edge>
<edge id="e302" source="n79" target="n31">
</edge>
<edge id="e303" source="n79" target="n43">
</edge>
<edge id="e304" source="n79" target="n30">
</edge>
<edge id="e305" source="n79" target="n19">
</edge>
<edge id="e306" source="n79" target="n29">
</edge>
<edge id="e307" source="n79" target="n35">
</edge>
<edge id="e308" source="n79" target="n55">
</edge>
<edge id="e309" source="n80" target="n79">
</edge>
<edge id="e310" source="n80" target="n37">
</edge>
<edge id="e311" source="n80" target="n29">
</edge>
<edge id="e312" source="n81" target="n16">
</edge>
<edge id="e313" source="n81" target="n5">
</edge>
<edge id="e314" source="n81" target="n40">
</edge>
<edge id="e315" source="n81" target="n10">
</edge>
<edge id="e316" source="n81" target="n72">
</edge>
<edge id="e317" source="n81" target="n3">
</edge>
<edge id="e318" source="n82" target="n81">
</edge>
<edge id="e319" source="n82" target="n74">
</edge>
<edge id="e320" source="n82" target="n39">
</edge>
<edge id="e321" source="n82" target="n77">
</edge>
<edge id="e322" source="n82" target="n80">
</edge>
<edge id="e323" source="n82" target="n30">
</edge>
<edge id="e324" source="n82" target="n29">
</edge>
<edge id="e325" source="n82" target="n7">
</edge>
<edge id="e326" source="n83" target="n53">
</edge>
<edge id="e327" source="n83" target="n81">
</edge>
<edge id="e328" source="n83" target="n69">
</edge>
<edge id="e329" source="n83" target="n73">
</edge>
<edge id="e330" source="n83" target="n46">
</edge>
<edge id="e331" source="n83" target="n67">
</edge>
<edge id="e332" source="n83" target="n49">
</edge>
<edge id="e333" source="n84" target="n83">
</edge>
<edge id="e334" source="n84" target="n24">
</edge>
<edge id="e335" source="n84" target="n49">
</edge>
<edge id="e336" source="n84" target="n52">
</edge>
<edge id="e337" source="n84" target="n3">
</edge>
<edge id="e338" source="n84" target="n74">
</edge>
<edge id="e339" source="n84" target="n10">
</edge>
<edge id="e340" source="n84" target="n81">
</edge>
<edge id="e341" source="n84" target="n5">
</edge>
<edge id="e342" source="n85" target="n6">
</edge>
<edge id="e343" source="n85" target="n14">
</edge>
<edge id="e344" source="n85" target="n38">
</edge>
<edge id="e345" source="n85" target="n43">
</edge>
<edge id="e346" source="n85" target="n80">
</edge>
<edge id="e347" source="n85" target="n12">
</edge>
<edge id="e348" source="n85" target="n26">
</edge>
<edge id="e349" source="n85" target="n31">
</edge>
<edge id="e350" source="n86" target="n44">
</edge>
<edge id="e351" source="n86" target="n53">
</edge>
<edge id="e352" source="n86" target="n75">
</edge>
<edge id="e353" source="n86" target="n57">
</edge>
<edge id="e354" source="n86" target="n48">
</edge>
<edge id="e355" source="n86" target="n80">
</edge>
<edge id="e356" source="n86" target="n66">
</edge>
<edge id="e357" source="n87" target="n86">
</edge>
<edge id="e358" source="n87" target="n17">
</edge>
<edge id="e359" source="n87" target="n62">
</edge>
<edge id="e360" source="n87" target="n56">
</edge>
<edge id="e361" source="n87" target="n24">
</edge>
<edge id="e362" source="n87" target="n20">
</edge>
<edge id="e363" source="n87" target="n65">
</edge>
<edge id="e364" source="n88" target="n49">
</edge>
<edge id="e365" source="n88" target="n58">
</edge>
<edge id="e366" source="n88" target="n83">
</edge>
<edge id="e367" source="n88" target="n69">
</edge>
<edge id="e368" source="n88" target="n46">
</edge>
<edge id="e369" source="n88" target="n53">
</edge>
<edge id="e370" source="n88" target="n73">
</edge>
<edge id="e371" source="n88" target="n67">
</edge>
<edge id="e372" source="n89" target="n88">
</edge>
<edge id="e373" source="n89" target="n1">
</edge>
<edge id="e374" source="n89" target="n37">
</edge>
<edge id="e375" source="n89" target="n25">
</edge>
<edge id="e376" source="n89" target="n33">
</edge>
<edge id="e377" source="n89" target="n55">
</edge>
<edge id="e378" source="n89" target="n45">
</edge>
<edge id="e379" source="n90" target="n5">
</edge>
<edge id="e380" source="n90" target="n8">
</edge>
<edge id="e381" source="n90" target="n23">
</edge>
<edge id="e382" source="n90" target="n0">
</edge>
<edge id="e383" source="n90" target="n11">
</edge>
<edge id="e384" source="n90" target="n50">
</edge>
<edge id="e385" source="n90" target="n24">
</edge>
<edge id="e386" source="n90" target="n69">
</edge>
<edge id="e387" source="n90" target="n28">
</edge>
<edge id="e388" source="n91" target="n29">
</edge>
<edge id="e389" source="n91" target="n48">
</edge>
<edge id="e390" source="n91" target="n66">
</edge>
<edge id="e391" source="n91" target="n69">
</edge>
<edge id="e392" source="n91" target="n44">
</edge>
<edge id="e393" source="n91" target="n86">
</edge>
<edge id="e394" source="n91" target="n57">
</edge>
<edge id="e395" source="n91" target="n80">
</edge>
<edge id="e396" source="n92" target="n91">
</edge>
<edge id="e397" source="n92" target="n35">
</edge>
<edge id="e398" source="n92" target="n15">
</edge>
<edge id="e399" source="n92" target="n86">
</edge>
<edge id="e400" source="n92" target="n48">
</edge>
<edge id="e401" source="n92" target="n57">
</edge>
<edge id="e402" source="n92" target="n61">
</edge>
<edge id="e403" source="n92" target="n66">
</edge>
<edge id="e404" source="n92" target="n75">
</edge>
<edge id="e405" source="n93" target="n0">
</edge>
<edge id="e406" source="n93" target="n23">
</edge>
<edge id="e407" source="n93" target="n80">
</edge>
<edge id="e408" source="n93" target="n16">
</edge>
<edge id="e409" source="n93" target="n4">
</edge>
<edge id="e410" source="n93" target="n82">
</edge>
<edge id="e411" source="n93" target="n91">
</edge>
<edge id="e412" source="n93" target="n41">
</edge>
<edge id="e413" source="n93" target="n9">
</edge>
<edge id="e414" source="n94" target="n34">
</edge>
<edge id="e415" source="n94" target="n19">
</edge>
<edge id="e416" source="n94" target="n55">
</edge>
<edge id="e417" source="n94" target="n79">
</edge>
<edge id="e418" source="n94" target="n80">
</edge>
<edge id="e419" source="n94" target="n29">
</edge>
<edge id="e420" source="n94" target="n30">
</edge>
<edge id="e421" source="n94" target="n82">
</edge>
<edge id="e422" source="n94" target="n35">
</edge>
<edge id="e423" source="n95" target="n70">
</edge>
<edge id="e424" source="n95" target="n69">
</edge>
<edge id="e425" source="n95" target="n76">
</edge>
<edge id="e426" source="n95" target="n62">
</edge>
<edge id="e427" source="n95" target="n56">
</edge>
<edge id="e428" source="n95" target="n27">
</edge>
<edge id="e429" source="n95" target="n17">
</edge>
<edge id="e430" source="n95" target="n87">
</edge>
<edge id="e431" source="n95" target="n37">
</edge>
<edge id="e432" source="n96" target="n48">
</edge>
<edge id="e433" source="n96" target="n17">
</edge>
<edge id="e434" source="n96" target="n76">
</edge>
<edge id="e435" source="n96" target="n27">
</edge>
<edge id="e436" source="n96" target="n56">
</edge>
<edge id="e437" source="n96" target="n65">
</edge>
<edge id="e438" source="n96" target="n20">
</edge>
<edge id="e439" source="n96" target="n87">
</edge>
<edge id="e440" source="n97" target="n5">
</edge>
<edge id="e441" source="n97" target="n86">
</edge>
<edge id="e442" source="n97" target="n58">
</edge>
<edge id="e443" source="n97" target="n11">
</edge>
<edge id="e444" source="n97" target="n59">
</edge>
<edge id="e445" source="n97" target="n63">
</edge>
<edge id="e446" source="n98" target="n97">
</edge>
<edge id="e447" source="n98" target="n77">
</edge>
<edge id="e448" source="n98" target="n48">
</edge>
<edge id="e449" source="n98" target="n84">
</edge>
<edge id="e450" source="n98" target="n40">
</edge>
<edge id="e451" source="n98" target="n10">
</edge>
<edge id="e452" source="n98" target="n5">
</edge>
<edge id="e453" source="n98" target="n52">
</edge>
<edge id="e454" source="n98" target="n81">
</edge>
<edge id="e455" source="n99" target="n89">
</edge>
<edge id="e456" source="n99" target="n34">
</edge>
<edge id="e457" source="n99" target="n14">
</edge>
<edge id="e458" source="n99" target="n85">
</edge>
<edge id="e459" source="n99" target="n54">
</edge>
<edge id="e460" source="n99" target="n18">
</edge>
<edge id="e461" source="n99" target="n31">
</edge>
<edge id="e462" source="n99" target="n61">
</edge>
<edge id="e463" source="n99" target="n71">
</edge>
<edge id="e464" source="n100" target="n99">
</edge>
<edge id="e465" source="n100" target="n82">
</edge>
<edge id="e466" source="n100" target="n13">
</edge>
<edge id="e467" source="n100" target="n2">
</edge>
<edge id="e468" source="n100" target="n15">
</edge>
<edge id="e469" source="n100" target="n32">
</edge>
<edge id="e470" source="n100" target="n64">
</edge>
<edge id="e471" source="n100" target="n47">
</edge>
<edge id="e472" source="n100" target="n39">
</edge>
<edge id="e473" source="n100" target="n6">
</edge>
<edge id="e474" source="n101" target="n51">
</edge>
<edge id="e475" source="n101" target="n30">
</edge>
<edge id="e476" source="n101" target="n94">
</edge>
<edge id="e477" source="n101" target="n1">
</edge>
<edge id="e478" source="n101" target="n79">
</edge>
<edge id="e479" source="n101" target="n58">
</edge>
<edge id="e480" source="n101" target="n19">
</edge>
<edge id="e481" source="n101" target="n55">
</edge>
<edge id="e482" source="n101" target="n35">
</edge>
<edge id="e483" source="n101" target="n29">
</edge>
<edge id="e484" source="n102" target="n100">
</edge>
<edge id="e485" source="n102" target="n74">
</edge>
<edge id="e486" source="n102" target="n52">
</edge>
<edge id="e487" source="n102" target="n98">
</edge>
<edge id="e488" source="n102" target="n72">
</edge>
<edge id="e489" source="n102" target="n40">
</edge>
<edge id="e490" source="n102" target="n10">
</edge>
<edge id="e491" source="n102" target="n3">
</edge>
<edge id="e492" source="n103" target="n102">
</edge>
<edge id="e493" source="n103" target="n33">
</edge>
<edge id="e494" source="n103" target="n45">
</edge>
<edge id="e495" source="n103" target="n25">
</edge>
<edge id="e496" source="n103" target="n89">
</edge>
<edge id="e497" source="n103" target="n37">
</edge>
<edge id="e498" source="n103" target="n1">
</edge>
<edge id="e499" source="n103" target="n70">
</edge>
<edge id="e500" source="n104" target="n72">
</edge>
<edge id="e501" source="n104" target="n11">
</edge>
<edge id="e502" source="n104" target="n0">
</edge>
<edge id="e503" source="n104" target="n93">
</edge>
<edge id="e504" source="n104" target="n67">
</edge>
<edge id="e505" source="n104" target="n41">
</edge>
<edge id="e506" source="n104" target="n16">
</edge>
<edge id="e507" source="n104" target="n87">
</edge>
<edge id="e508" source="n104" target="n23">
</edge>
<edge id="e509" source="n104" target="n4">
</edge>
<edge id="e510" source="n104" target="n9">
</edge>
<edge id="e511" source="n105" target="n89">
</edge>
<edge id="e512" source="n105" target="n103">
</edge>
<edge id="e513" source="n105" target="n33">
</edge>
<edge id="e514" source="n105" target="n62">
</edge>
<edge id="e515" source="n105" target="n37">
</edge>
<edge id="e516" source="n105" target="n45">
</edge>
<edge id="e517" source="n105" target="n1">
</edge>
<edge id="e518" source="n105" target="n80">
</edge>
<edge id="e519" source="n105" target="n25">
</edge>
<edge id="e520" source="n106" target="n25">
</edge>
<edge id="e521" source="n106" target="n56">
</edge>
<edge id="e522" source="n106" target="n92">
</edge>
<edge id="e523" source="n106" target="n2">
</edge>
<edge id="e524" source="n106" target="n13">
</edge>
<edge id="e525" source="n106" target="n32">
</edge>
<edge id="e526" source="n106" target="n60">
</edge>
<edge id="e527" source="n106" target="n6">
</edge>
<edge id="e528" source="n106" target="n64">
</edge>
<edge id="e529" source="n106" target="n15">
</edge>
<edge id="e530" source="n106" target="n39">
</edge>
<edge id="e531" source="n107" target="n88">
</edge>
<edge id="e532" source="n107" target="n75">
</edge>
<edge id="e533" source="n107" target="n98">
</edge>
<edge id="e534" source="n107" target="n102">
</edge>
<edge id="e535" source="n107" target="n72">
</edge>
<edge id="e536" source="n107" target="n40">
</edge>
<edge id="e537" source="n107" target="n81">
</edge>
<edge id="e538" source="n107" target="n5">
</edge>
<edge id="e539" source="n107" target="n10">
</edge>
<edge id="e540" source="n107" target="n84">
</edge>
<edge id="e541" source="n108" target="n4">
</edge>
<edge id="e542" source="n108" target="n9">
</edge>
<edge id="e543" source="n108" target="n7">
</edge>
<edge id="e544" source="n108" target="n51">
</edge>
<edge id="e545" source="n108" target="n77">
</edge>
<edge id="e546" source="n108" target="n21">
</edge>
<edge id="e547" source="n108" target="n78">
</edge>
<edge id="e548" source="n108" target="n22">
</edge>
<edge id="e549" source="n108" target="n68">
</edge>
<edge id="e550" source="n109" target="n79">
</edge>
<edge id="e551" source="n109" target="n30">
</edge>
<edge id="e552" source="n109" target="n63">
</edge>
<edge id="e553" source="n109" target="n1">
</edge>
<edge id="e554" source="n109" target="n33">
</edge>
<edge id="e555" source="n109" target="n103">
</edge>
<edge id="e556" source="n109" target="n105">
</edge>
<edge id="e557" source="n109" target="n45">
</edge>
<edge id="e558" source="n109" target="n25">
</edge>
<edge id="e559" source="n109" target="n89">
</edge>
<edge id="e560" source="n109" target="n37">
</edge>
<edge id="e561" source="n110" target="n67">
</edge>
<edge id="e562" source="n110" target="n13">
</edge>
<edge id="e563" source="n110" target="n24">
</edge>
<edge id="e564" source="n110" target="n80">
</edge>
<edge id="e565" source="n110" target="n88">
</edge>
<edge id="e566" source="n110" target="n49">
</edge>
<edge id="e567" source="n110" target="n73">
</edge>
<edge id="e568" source="n110" target="n46">
</edge>
<edge id="e569" source="n110" target="n83">
</edge>
<edge id="e570" source="n110" target="n53">
</edge>
<edge id="e571" source="n111" target="n23">
</edge>
<edge id="e572" source="n111" target="n64">
</edge>
<edge id="e573" source="n111" target="n46">
</edge>
<edge id="e574" source="n111" target="n78">
</edge>
<edge id="e575" source="n111" target="n8">
</edge>
<edge id="e576" source="n111" target="n21">
</edge>
<edge id="e577" source="n111" target="n51">
</edge>
<edge id="e578" source="n111" target="n7">
</edge>
<edge id="e579" source="n111" target="n108">
</edge>
<edge id="e580" source="n111" target="n68">
</edge>
<edge id="e581" source="n111" target="n77">
</edge>
<edge id="e582" source="n112" target="n52">
</edge>
<edge id="e583" source="n112" target="n96">
</edge>
<edge id="e584" source="n112" target="n97">
</edge>
<edge id="e585" source="n112" target="n57">
</edge>
<edge id="e586" source="n112" target="n66">
</edge>
<edge id="e587" source="n112" target="n63">
</edge>
<edge id="e588" source="n112" target="n44">
</edge>
<edge id="e589" source="n112" target="n92">
</edge>
<edge id="e590" source="n112" target="n75">
</edge>
<edge id="e591" source="n112" target="n91">
</edge>
<edge id="e592" source="n113" target="n28">
</edge>
<edge id="e593" source="n113" target="n20">
</edge>
<edge id="e594" source="n113" target="n95">
</edge>
<edge id="e595" source="n113" target="n59">
</edge>
<edge id="e596" source="n113" target="n70">
</edge>
<edge id="e597" source="n113" target="n17">
</edge>
<edge id="e598" source="n113" target="n87">
</edge>
<edge id="e599" source="n113" target="n76">
</edge>
<edge id="e600" source="n113" target="n65">
</edge>
<edge id="e601" source="n113" target="n96">
</edge>
<edge id="e602" source="n114" target="n83">
</edge>
<edge id="e603" source="n114" target="n88">
</edge>
<edge id="e604" source="n114" target="n110">
</edge>
<edge id="e605" source="n114" target="n53">
</edge>
<edge id="e606" source="n114" target="n49">
</edge>
<edge id="e607" source="n114" target="n73">
</edge>
<edge id="e608" source="n114" target="n46">
</edge>
<edge id="e609" source="n114" target="n67">
</edge>
<edge id="e610" source="n114" target="n58">
</edge>
<edge id="e611" source="n114" target="n15">
</edge>
<edge id="e612" source="n114" target="n104">
</edge>
</graph>
</graphml>
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<!-- property keys -->
<key id="key0" for="graph" attr.name="dl" attr.type="float" />
<key id="key1" for="node" attr.name="partition" attr.type="int" />
<graph id="G" edgedefault="undirected" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
<!-- graph properties -->
<data key="key0">229.04187438186472</data>
<!-- vertices -->
<node id="n0">
<data key="key1">1</data>
</node>
<node id="n1">
<data key="key1">1</data>
</node>
<node id="n2">
<data key="key1">1</data>
</node>
<node id="n3">
<data key="key1">0</data>
</node>
<node id="n4">
<data key="key1">2</data>
</node>
<node id="n5">
<data key="key1">0</data>
</node>
<node id="n6">
<data key="key1">1</data>
</node>
<node id="n7">
<data key="key1">0</data>
</node>
<node id="n8">
<data key="key1">1</data>
</node>
<node id="n9">
<data key="key1">2</data>
</node>
<node id="n10">
<data key="key1">2</data>
</node>
<node id="n11">
<data key="key1">0</data>
</node>
<node id="n12">
<data key="key1">1</data>
</node>
<node id="n13">
<data key="key1">1</data>
</node>
<node id="n14">
<data key="key1">3</data>
</node>
<node id="n15">
<data key="key1">0</data>
</node>
<node id="n16">
<data key="key1">0</data>
</node>
<node id="n17">
<data key="key1">2</data>
</node>
<node id="n18">
<data key="key1">2</data>
</node>
<node id="n19">
<data key="key1">1</data>
</node>
<node id="n20">
<data key="key1">0</data>
</node>
<node id="n21">
<data key="key1">1</data>
</node>
<node id="n22">
<data key="key1">2</data>
</node>
<node id="n23">
<data key="key1">0</data>
</node>
<node id="n24">
<data key="key1">2</data>
</node>
<node id="n25">
<data key="key1">0</data>
</node>
<node id="n26">
<data key="key1">0</data>
</node>
<!-- edges -->
<edge id="e0" source="n0" target="n6">
</edge>
<edge id="e1" source="n0" target="n13">
</edge>
<edge id="e2" source="n0" target="n1">
</edge>
<edge id="e3" source="n0" target="n2">
</edge>
<edge id="e4" source="n0" target="n8">
</edge>
<edge id="e5" source="n0" target="n14">
</edge>
<edge id="e6" source="n0" target="n19">
</edge>
<edge id="e7" source="n1" target="n2">
</edge>
<edge id="e8" source="n1" target="n6">
</edge>
<edge id="e9" source="n1" target="n12">
</edge>
<edge id="e10" source="n1" target="n13">
</edge>
<edge id="e11" source="n1" target="n14">
</edge>
<edge id="e12" source="n1" target="n8">
</edge>
<edge id="e13" source="n1" target="n19">
</edge>
<edge id="e14" source="n2" target="n6">
</edge>
<edge id="e15" source="n2" target="n13">
</edge>
<edge id="e16" source="n2" target="n8">
</edge>
<edge id="e17" source="n2" target="n14">
</edge>
<edge id="e18" source="n2" target="n19">
</edge>
<edge id="e19" source="n3" target="n5">
</edge>
<edge id="e20" source="n3" target="n15">
</edge>
<edge id="e21" source="n3" target="n26">
</edge>
<edge id="e22" source="n3" target="n7">
</edge>
<edge id="e23" source="n3" target="n11">
</edge>
<edge id="e24" source="n4" target="n7">
</edge>
<edge id="e25" source="n4" target="n9">
</edge>
<edge id="e26" source="n4" target="n10">
</edge>
<edge id="e27" source="n4" target="n14">
</edge>
<edge id="e28" source="n4" target="n17">
</edge>
<edge id="e29" source="n4" target="n22">
</edge>
<edge id="e30" source="n4" target="n24">
</edge>
<edge id="e31" source="n4" target="n18">
</edge>
<edge id="e32" source="n5" target="n7">
</edge>
<edge id="e33" source="n5" target="n14">
</edge>
<edge id="e34" source="n5" target="n23">
</edge>
<edge id="e35" source="n5" target="n25">
</edge>
<edge id="e36" source="n5" target="n11">
</edge>
<edge id="e37" source="n5" target="n15">
</edge>
<edge id="e38" source="n5" target="n26">
</edge>
<edge id="e39" source="n6" target="n13">
</edge>
<edge id="e40" source="n6" target="n8">
</edge>
<edge id="e41" source="n6" target="n14">
</edge>
<edge id="e42" source="n6" target="n19">
</edge>
<edge id="e43" source="n7" target="n9">
</edge>
<edge id="e44" source="n7" target="n10">
</edge>
<edge id="e45" source="n7" target="n14">
</edge>
<edge id="e46" source="n7" target="n15">
</edge>
<edge id="e47" source="n7" target="n16">
</edge>
<edge id="e48" source="n7" target="n17">
</edge>
<edge id="e49" source="n7" target="n20">
</edge>
<edge id="e50" source="n7" target="n22">
</edge>
<edge id="e51" source="n7" target="n25">
</edge>
<edge id="e52" source="n7" target="n26">
</edge>
<edge id="e53" source="n7" target="n8">
</edge>
<edge id="e54" source="n7" target="n11">
</edge>
<edge id="e55" source="n7" target="n12">
</edge>
<edge id="e56" source="n7" target="n18">
</edge>
<edge id="e57" source="n7" target="n19">
</edge>
<edge id="e58" source="n7" target="n21">
</edge>
<edge id="e59" source="n7" target="n23">
</edge>
<edge id="e60" source="n7" target="n24">
</edge>
<edge id="e61" source="n8" target="n12">
</edge>
<edge id="e62" source="n8" target="n13">
</edge>
<edge id="e63" source="n8" target="n14">
</edge>
<edge id="e64" source="n8" target="n19">
</edge>
<edge id="e65" source="n8" target="n21">
</edge>
<edge id="e66" source="n9" target="n10">
</edge>
<edge id="e67" source="n9" target="n17">
</edge>
<edge id="e68" source="n9" target="n22">
</edge>
<edge id="e69" source="n9" target="n14">
</edge>
<edge id="e70" source="n9" target="n18">
</edge>
<edge id="e71" source="n9" target="n24">
</edge>
<edge id="e72" source="n10" target="n17">
</edge>
<edge id="e73" source="n10" target="n22">
</edge>
<edge id="e74" source="n10" target="n14">
</edge>
<edge id="e75" source="n10" target="n18">
</edge>
<edge id="e76" source="n10" target="n24">
</edge>
<edge id="e77" source="n11" target="n15">
</edge>
<edge id="e78" source="n11" target="n16">
</edge>
<edge id="e79" source="n11" target="n20">
</edge>
<edge id="e80" source="n11" target="n26">
</edge>
<edge id="e81" source="n12" target="n19">
</edge>
<edge id="e82" source="n12" target="n21">
</edge>
<edge id="e83" source="n13" target="n14">
</edge>
<edge id="e84" source="n13" target="n19">
</edge>
<edge id="e85" source="n14" target="n17">
</edge>
<edge id="e86" source="n14" target="n22">
</edge>
<edge id="e87" source="n14" target="n25">
</edge>
<edge id="e88" source="n14" target="n18">
</edge>
<edge id="e89" source="n14" target="n19">
</edge>
<edge id="e90" source="n14" target="n23">
</edge>
<edge id="e91" source="n14" target="n24">
</edge>
<edge id="e92" source="n15" target="n26">
</edge>
<edge id="e93" source="n16" target="n20">
</edge>
<edge id="e94" source="n17" target="n18">
</edge>
<edge id="e95" source="n17" target="n22">
</edge>
<edge id="e96" source="n17" target="n24">
</edge>
<edge id="e97" source="n18" target="n22">
</edge>
<edge id="e98" source="n18" target="n24">
</edge>
<edge id="e99" source="n19" target="n21">
</edge>
<edge id="e100" source="n22" target="n24">
</edge>
<edge id="e101" source="n23" target="n25">
</edge>
</graph>
</graphml>
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<!-- property keys -->
<key id="key0" for="graph" attr.name="dl" attr.type="float" />
<key id="key1" for="node" attr.name="partition" attr.type="int" />
<graph id="G" edgedefault="undirected" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
<!-- graph properties -->
<data key="key0">43.479327707987835</data>
<!-- vertices -->
<node id="n0">
<data key="key1">0</data>
</node>
<node id="n1">
<data key="key1">0</data>
</node>
<node id="n2">
<data key="key1">0</data>
</node>
<node id="n3">
<data key="key1">0</data>
</node>
<node id="n4">
<data key="key1">0</data>
</node>
<node id="n5">
<data key="key1">1</data>
</node>
<node id="n6">
<data key="key1">1</data>
</node>
<node id="n7">
<data key="key1">1</data>
</node>
<node id="n8">
<data key="key1">1</data>
</node>
<node id="n9">
<data key="key1">1</data>
</node>
<!-- edges -->
<edge id="e0" source="n0" target="n1">
</edge>
<edge id="e1" source="n0" target="n2">
</edge>
<edge id="e2" source="n0" target="n3">
</edge>
<edge id="e3" source="n0" target="n4">
</edge>
<edge id="e4" source="n1" target="n2">
</edge>
<edge id="e5" source="n1" target="n3">
</edge>
<edge id="e6" source="n1" target="n4">
</edge>
<edge id="e7" source="n2" target="n3">
</edge>
<edge id="e8" source="n2" target="n4">
</edge>
<edge id="e9" source="n3" target="n4">
</edge>
<edge id="e10" source="n5" target="n6">
</edge>
<edge id="e11" source="n5" target="n7">
</edge>
<edge id="e12" source="n5" target="n8">
</edge>
<edge id="e13" source="n5" target="n9">
</edge>
<edge id="e14" source="n6" target="n7">
</edge>
<edge id="e15" source="n6" target="n8">
</edge>
<edge id="e16" source="n6" target="n9">
</edge>
<edge id="e17" source="n7" target="n8">
</edge>
<edge id="e18" source="n7" target="n9">
</edge>
<edge id="e19" source="n8" target="n9">
</edge>
</graph>
</graphml>
......@@ -104,7 +104,7 @@ public class ModularityUI implements StatisticsUI {
@Override
public String getCategory() {
return StatisticsUI.CATEGORY_NETWORK_OVERVIEW;
return StatisticsUI.CATEGORY_COMMUNITY_DETECTION;
}
@Override
......
/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2011 Gephi Consortium. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License. When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.
Contributor(s):
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.ui.statistics.plugin;
import java.text.DecimalFormat;
import javax.swing.JPanel;
import org.gephi.statistics.plugin.StatisticalInferenceClustering;
import org.gephi.statistics.spi.Statistics;
import org.gephi.statistics.spi.StatisticsUI;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
@ServiceProvider(service = StatisticsUI.class)
public class StatisticalInferenceClusteringUI implements StatisticsUI {
StatisticalInferenceClustering descriptionLength;
@Override
public JPanel getSettingsPanel() {
return null;
}
@Override
public void setup(Statistics statistics) {
this.descriptionLength = (StatisticalInferenceClustering) statistics;
}
@Override
public void unsetup() {
descriptionLength = null;
}
@Override
public Class<? extends Statistics> getStatisticsClass() {
return StatisticalInferenceClustering.class;
}
@Override
public String getValue() {
DecimalFormat df = new DecimalFormat("###.###");
return "" + df.format(descriptionLength.getDescriptionLength());
}
@Override
public String getDisplayName() {
return NbBundle.getMessage(getClass(), "StatisticalInferenceClusteringUI.name");
}
@Override
public String getCategory() {
return StatisticsUI.CATEGORY_COMMUNITY_DETECTION;
}
@Override
public int getPosition() {
return 600;
}
@Override
public String getShortDescription() {
return NbBundle.getMessage(getClass(), "StatisticalInferenceClusteringUI.shortDescription");
}
}
......@@ -78,6 +78,8 @@ InOutDegreeUI.name=Average Degree
InOutDegreeUI.shortDescription=Average Degree
ModularityUI.name=Modularity
ModularityUI.shortDescription=Community detection algorithm.
StatisticalInferenceClusteringUI.name=Statistical Inference
StatisticalInferenceClusteringUI.shortDescription=Community detection algorithm.
PageRankUI.name=PageRank
PageRankUI.shortDescription=Ranks nodes "pages" according to how often a user following links will non-randomly reach the node "page".
PathLengthUI.name=Avg. Path Length
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册