diff --git a/modules/ImportPlugin/src/main/java/org/gephi/io/importer/plugin/file/ImporterCSV.java b/modules/ImportPlugin/src/main/java/org/gephi/io/importer/plugin/file/ImporterCSV.java index 1dbf9794942015a0d639f05f2a8a50926f732889..ee8c384cfc14ed8a64c558e44444614566bef2d3 100644 --- a/modules/ImportPlugin/src/main/java/org/gephi/io/importer/plugin/file/ImporterCSV.java +++ b/modules/ImportPlugin/src/main/java/org/gephi/io/importer/plugin/file/ImporterCSV.java @@ -44,6 +44,7 @@ package org.gephi.io.importer.plugin.file; import java.io.IOException; import java.io.LineNumberReader; import java.io.Reader; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -126,7 +127,9 @@ public class ImporterCSV implements FileImporter, LongTask { int size = lines.size(); if (size != labels.size()) { - throw new Exception("Inconsistent number of matrix lines compared to the number of labels."); + throw new Exception( + MessageFormat.format("Inconsistent number of matrix lines compared to the number of labels. {0} lines, {1} labels", size, labels.size()) + ); } for (int i = 0; i < size; i++) { diff --git a/modules/LayoutAPI/src/main/java/org/gephi/layout/LayoutModelImpl.java b/modules/LayoutAPI/src/main/java/org/gephi/layout/LayoutModelImpl.java index 72774daef93e353a02ce1dc37ca02a2e5212aac4..25a0ecfea1896a302ae0a5cf2fc8d2846c900e80 100644 --- a/modules/LayoutAPI/src/main/java/org/gephi/layout/LayoutModelImpl.java +++ b/modules/LayoutAPI/src/main/java/org/gephi/layout/LayoutModelImpl.java @@ -55,6 +55,7 @@ import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.events.XMLEvent; import org.gephi.graph.api.GraphController; +import org.gephi.graph.api.GraphModel; import org.gephi.layout.api.LayoutModel; import org.gephi.layout.spi.Layout; import org.gephi.layout.spi.LayoutBuilder; @@ -79,7 +80,7 @@ public class LayoutModelImpl implements LayoutModel { private final Map savedProperties; private Layout selectedLayout; private LayoutBuilder selectedBuilder; - private Workspace workspace; + private final Workspace workspace; //Util private final LongTaskExecutor executor; @@ -116,6 +117,9 @@ public class LayoutModelImpl implements LayoutModel { @Override public Layout getLayout(LayoutBuilder layoutBuilder) { Layout layout = layoutBuilder.buildLayout(); + GraphController graphController = Lookup.getDefault().lookup(GraphController.class); + GraphModel graphModel = graphController.getGraphModel(workspace); + layout.setGraphModel(graphModel); selectedBuilder = layoutBuilder; layout.resetPropertiesValues(); return layout; diff --git a/modules/StatisticsPlugin/src/main/java/org/gephi/statistics/plugin/Modularity.java b/modules/StatisticsPlugin/src/main/java/org/gephi/statistics/plugin/Modularity.java index 920db6ca0e7146baaae04ffab37b4834c331ecc1..8cab95ca54f0e569cc7c479b4fd85d21cc0991cf 100644 --- a/modules/StatisticsPlugin/src/main/java/org/gephi/statistics/plugin/Modularity.java +++ b/modules/StatisticsPlugin/src/main/java/org/gephi/statistics/plugin/Modularity.java @@ -133,26 +133,27 @@ public class Modularity implements Statistics, LongTask { Graph graph; double[] weights; double graphWeightSum; - LinkedList[] topology; - LinkedList communities; + List[] topology; + List communities; int N; HashMap invMap; - CommunityStructure(Graph hgraph) { - this.graph = hgraph; - N = hgraph.getNodeCount(); + CommunityStructure(Graph graph) { + this.graph = graph; + N = graph.getNodeCount(); invMap = new HashMap<>(); nodeConnectionsWeight = new HashMap[N]; nodeConnectionsCount = new HashMap[N]; nodeCommunities = new Community[N]; map = new HashMap<>(); - topology = new LinkedList[N]; - communities = new LinkedList<>(); + topology = new ArrayList[N]; + communities = new ArrayList<>(); int index = 0; weights = new double[N]; - for (Node node : hgraph.getNodes()) { + for (Node node : graph.getNodes()) { map.put(node, index); nodeCommunities[index] = new Community(this); + nodeConnectionsWeight[index] = new HashMap<>(); nodeConnectionsCount[index] = new HashMap<>(); weights[index] = 0; @@ -167,34 +168,47 @@ public class Modularity implements Statistics, LongTask { } } - for (Node node : hgraph.getNodes()) { + for (Node node : graph.getNodes()) { int node_index = map.get(node); - topology[node_index] = new LinkedList<>(); - - for (Edge edge : hgraph.getEdges(node)) { - Node neighbor = hgraph.getOpposite(node, edge); + topology[node_index] = new ArrayList<>(); + Set uniqueNeighbors = new HashSet<>(graph.getNeighbors(node).toCollection()); + for (Node neighbor : uniqueNeighbors) { if (node == neighbor) { continue; } int neighbor_index = map.get(neighbor); - float weight = 1; - if (useWeight) { - weight = (float) edge.getWeight(graph.getView()); + float weight = 0; + + //Sum all parallel edges weight: + for (Edge edge : graph.getEdges(node, neighbor)) { + if (useWeight) { + 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; Modularity.ModEdge me = new ModEdge(node_index, neighbor_index, weight); topology[node_index].add(me); Community adjCom = nodeCommunities[neighbor_index]; + nodeConnectionsWeight[node_index].put(adjCom, weight); nodeConnectionsCount[node_index].put(adjCom, 1); - nodeCommunities[node_index].connectionsWeight.put(adjCom, weight); - nodeCommunities[node_index].connectionsCount.put(adjCom, 1); - nodeConnectionsWeight[neighbor_index].put(nodeCommunities[node_index], weight); - nodeConnectionsCount[neighbor_index].put(nodeCommunities[node_index], 1); - nodeCommunities[neighbor_index].connectionsWeight.put(nodeCommunities[node_index], weight); - nodeCommunities[neighbor_index].connectionsCount.put(nodeCommunities[node_index], 1); + + Community nodeCom = nodeCommunities[node_index]; + nodeCom.connectionsWeight.put(adjCom, weight); + nodeCom.connectionsCount.put(adjCom, 1); + + nodeConnectionsWeight[neighbor_index].put(nodeCom, weight); + nodeConnectionsCount[neighbor_index].put(nodeCom, 1); + + adjCom.connectionsWeight.put(nodeCom, weight); + adjCom.connectionsCount.put(nodeCom, 1); + graphWeightSum += weight; } @@ -206,7 +220,7 @@ public class Modularity implements Statistics, LongTask { } private void addNodeTo(int node, Community to) { - to.add(new Integer(node)); + to.add(node); nodeCommunities[node] = to; for (ModEdge e : topology[node]) { @@ -276,8 +290,7 @@ public class Modularity implements Statistics, LongTask { } } - private void removeNodeFrom(int node, Community from) { - + private void removeNodeFromItsCommunity(int node) { Community community = nodeCommunities[node]; for (ModEdge e : topology[node]) { int neighbor = e.target; @@ -334,18 +347,17 @@ public class Modularity implements Statistics, LongTask { } } - from.remove(new Integer(node)); + community.remove(node); } private void moveNodeTo(int node, Community to) { - Community from = nodeCommunities[node]; - removeNodeFrom(node, from); + removeNodeFromItsCommunity(node); addNodeTo(node, to); } private void zoomOut() { int M = communities.size(); - LinkedList[] newTopology = new LinkedList[M]; + ArrayList[] newTopology = new ArrayList[M]; int index = 0; nodeCommunities = new Community[M]; nodeConnectionsWeight = new HashMap[M]; @@ -355,7 +367,8 @@ public class Modularity implements Statistics, LongTask { Community com = communities.get(i); nodeConnectionsWeight[index] = new HashMap<>(); nodeConnectionsCount[index] = new HashMap<>(); - newTopology[index] = new LinkedList<>(); + + newTopology[index] = new ArrayList<>(); nodeCommunities[index] = new Community(com); Set iter = com.connectionsWeight.keySet(); double weightSum = 0; @@ -406,7 +419,7 @@ public class Modularity implements Statistics, LongTask { double weightSum; CommunityStructure structure; - LinkedList nodes; + List nodes; HashMap connectionsWeight; HashMap connectionsCount; @@ -418,7 +431,7 @@ public class Modularity implements Statistics, LongTask { structure = com.structure; connectionsWeight = new HashMap<>(); connectionsCount = new HashMap<>(); - nodes = new LinkedList<>(); + nodes = new ArrayList<>(); //mHidden = pCom.mHidden; } @@ -426,7 +439,7 @@ public class Modularity implements Statistics, LongTask { this.structure = structure; connectionsWeight = new HashMap<>(); connectionsCount = new HashMap<>(); - nodes = new LinkedList<>(); + nodes = new ArrayList<>(); } public void seed(int node) { @@ -435,13 +448,13 @@ public class Modularity implements Statistics, LongTask { } public boolean add(int node) { - nodes.addLast(new Integer(node)); + nodes.add(node); weightSum += structure.weights[node]; return true; } public boolean remove(int node) { - boolean result = nodes.remove(new Integer(node)); + boolean result = nodes.remove((Integer) node); weightSum -= structure.weights[node]; if (nodes.isEmpty()) { structure.communities.remove(this); @@ -452,29 +465,33 @@ public class Modularity implements Statistics, LongTask { @Override public void execute(GraphModel graphModel) { - Graph hgraph = graphModel.getUndirectedGraphVisible(); - execute(hgraph); + Graph graph = graphModel.getUndirectedGraphVisible(); + execute(graph); } - public void execute(Graph hgraph) { + public void execute(Graph graph) { isCanceled = false; - hgraph.readLock(); - - structure = new Modularity.CommunityStructure(hgraph); - int[] comStructure = new int[hgraph.getNodeCount()]; + graph.readLock(); - HashMap computedModularityMetrics = computeModularity(hgraph, structure, comStructure, resolution, isRandomized, useWeight); + structure = new Modularity.CommunityStructure(graph); + int[] comStructure = new int[graph.getNodeCount()]; - modularity = computedModularityMetrics.get("modularity"); - modularityResolution = computedModularityMetrics.get("modularityResolution"); + if (graph.getNodeCount() > 0) {//Fixes issue #713 Modularity Calculation Throws Exception On Empty Graph + HashMap computedModularityMetrics = computeModularity(graph, structure, comStructure, resolution, isRandomized, useWeight); + modularity = computedModularityMetrics.get("modularity"); + modularityResolution = computedModularityMetrics.get("modularityResolution"); + } else { + modularity = 0; + modularityResolution = 0; + } - saveValues(comStructure, hgraph, structure); + saveValues(comStructure, graph, structure); - hgraph.readUnlock(); + graph.readUnlock(); } - protected HashMap computeModularity(Graph hgraph, CommunityStructure theStructure, int[] comStructure, + protected HashMap computeModularity(Graph graph, CommunityStructure theStructure, int[] comStructure, double currentResolution, boolean randomized, boolean weighted) { isCanceled = false; Progress.start(progress); @@ -486,7 +503,7 @@ public class Modularity implements Statistics, LongTask { HashMap results = new HashMap<>(); if (isCanceled) { - hgraph.readUnlockAll(); + graph.readUnlockAll(); return results; } boolean someChange = true; @@ -508,13 +525,13 @@ public class Modularity implements Statistics, LongTask { localChange = true; } if (isCanceled) { - hgraph.readUnlockAll(); + graph.readUnlockAll(); return results; } } someChange = localChange || someChange; if (isCanceled) { - hgraph.readUnlockAll(); + graph.readUnlockAll(); return results; } } @@ -524,11 +541,11 @@ public class Modularity implements Statistics, LongTask { } } - fillComStructure(hgraph, theStructure, comStructure); - double[] degreeCount = fillDegreeCount(hgraph, theStructure, comStructure, nodeDegrees, weighted); + fillComStructure(graph, theStructure, comStructure); + double[] degreeCount = fillDegreeCount(graph, theStructure, comStructure, nodeDegrees, weighted); - double computedModularity = finalQ(comStructure, degreeCount, hgraph, theStructure, totalWeight, 1., weighted); - double computedModularityResolution = finalQ(comStructure, degreeCount, hgraph, theStructure, totalWeight, currentResolution, weighted); + double computedModularity = finalQ(comStructure, degreeCount, graph, theStructure, totalWeight, 1., weighted); + double computedModularityResolution = finalQ(comStructure, degreeCount, graph, theStructure, totalWeight, currentResolution, weighted); results.put("modularity", computedModularity); results.put("modularityResolution", computedModularityResolution); @@ -536,12 +553,12 @@ public class Modularity implements Statistics, LongTask { return results; } - Community updateBestCommunity(CommunityStructure theStructure, int i, double currentResolution) { + private Community updateBestCommunity(CommunityStructure theStructure, int node_id, double currentResolution) { double best = 0.; Community bestCommunity = null; - Set iter = theStructure.nodeConnectionsWeight[i].keySet(); + Set iter = theStructure.nodeConnectionsWeight[node_id].keySet(); for (Community com : iter) { - double qValue = q(i, com, theStructure, currentResolution); + double qValue = q(node_id, com, theStructure, currentResolution); if (qValue > best) { best = qValue; bestCommunity = com; @@ -550,8 +567,7 @@ public class Modularity implements Statistics, LongTask { return bestCommunity; } - int[] fillComStructure(Graph hgraph, CommunityStructure theStructure, int[] comStructure) { -// int[] comStructure = new int[hgraph.getNodeCount()]; + private int[] fillComStructure(Graph graph, CommunityStructure theStructure, int[] comStructure) { int count = 0; for (Community com : theStructure.communities) { @@ -566,37 +582,37 @@ public class Modularity implements Statistics, LongTask { return comStructure; } - double[] fillDegreeCount(Graph hgraph, CommunityStructure theStructure, int[] comStructure, double[] nodeDegrees, boolean weighted) { + private double[] fillDegreeCount(Graph graph, CommunityStructure theStructure, int[] comStructure, double[] nodeDegrees, boolean weighted) { double[] degreeCount = new double[theStructure.communities.size()]; - for (Node node : hgraph.getNodes()) { + for (Node node : graph.getNodes()) { int index = theStructure.map.get(node); if (weighted) { degreeCount[comStructure[index]] += nodeDegrees[index]; } else { - degreeCount[comStructure[index]] += hgraph.getDegree(node); + degreeCount[comStructure[index]] += graph.getDegree(node); } } return degreeCount; } - private double finalQ(int[] struct, double[] degrees, Graph hgraph, + private double finalQ(int[] struct, double[] degrees, Graph graph, CommunityStructure theStructure, double totalWeight, double usedResolution, boolean weighted) { double res = 0; double[] internal = new double[degrees.length]; - for (Node n : hgraph.getNodes()) { + for (Node n : graph.getNodes()) { int n_index = theStructure.map.get(n); - for (Edge edge : hgraph.getEdges(n)) { - Node neighbor = hgraph.getOpposite(n, edge); + for (Edge edge : graph.getEdges(n)) { + Node neighbor = graph.getOpposite(n, edge); if (n == neighbor) { continue; } int neigh_index = theStructure.map.get(neighbor); if (struct[neigh_index] == struct[n_index]) { if (weighted) { - internal[struct[neigh_index]] += edge.getWeight(hgraph.getView()); + internal[struct[neigh_index]] += edge.getWeight(graph.getView()); } else { internal[struct[neigh_index]]++; } @@ -610,13 +626,13 @@ public class Modularity implements Statistics, LongTask { return res; } - private void saveValues(int[] struct, Graph hgraph, CommunityStructure theStructure) { - Table nodeTable = hgraph.getModel().getNodeTable(); + private void saveValues(int[] struct, Graph graph, CommunityStructure theStructure) { + Table nodeTable = graph.getModel().getNodeTable(); Column modCol = nodeTable.getColumn(MODULARITY_CLASS); if (modCol == null) { - modCol = nodeTable.addColumn(MODULARITY_CLASS, "Modularity Class", Integer.class, new Integer(0)); + modCol = nodeTable.addColumn(MODULARITY_CLASS, "Modularity Class", Integer.class, 0); } - for (Node n : hgraph.getNodes()) { + for (Node n : graph.getNodes()) { int n_index = theStructure.map.get(n); n.setAttribute(modCol, struct[n_index]); } diff --git a/modules/StatisticsPlugin/src/test/java/org/gephi/statistics/plugin/ModularityNGTest.java b/modules/StatisticsPlugin/src/test/java/org/gephi/statistics/plugin/ModularityNGTest.java index e5a748f8b4ad05e1aa500a4c833cd0950feb9dfd..51eec3594887f2fd0f4982c9110b90a80b5507a6 100644 --- a/modules/StatisticsPlugin/src/test/java/org/gephi/statistics/plugin/ModularityNGTest.java +++ b/modules/StatisticsPlugin/src/test/java/org/gephi/statistics/plugin/ModularityNGTest.java @@ -250,22 +250,33 @@ public class ModularityNGTest { undirectedGraph.addNode(node7); undirectedGraph.addNode(node8); - Edge edge12 = graphModel.factory().newEdge(node1, node2, 0, 10.f, false); + //Test 3 parallel edges summing weight = 10 + //Related issue ==> #1419 Getting null pointer error when trying to calculate modularity + Edge edge12_1 = graphModel.factory().newEdge(node1, node2, 0, 2.f, false); + Edge edge12_2 = graphModel.factory().newEdge(node1, node2, 0, 5.f, false); + Edge edge12_3 = graphModel.factory().newEdge(node1, node2, 0, 3.f, false); + Edge edge23 = graphModel.factory().newEdge(node2, node3, false); Edge edge34 = graphModel.factory().newEdge(node3, node4, 0, 10.f, false); Edge edge45 = graphModel.factory().newEdge(node4, node5, false); Edge edge56 = graphModel.factory().newEdge(node5, node6, 0, 10.f, false); Edge edge67 = graphModel.factory().newEdge(node6, node7, false); - Edge edge78 = graphModel.factory().newEdge(node7, node8, 0, 10.f, false); + + //Test 2 parallel edges summing weight = 10 + Edge edge78_1= graphModel.factory().newEdge(node7, node8, 0, 5.f, false); + Edge edge78_2 = graphModel.factory().newEdge(node7, node8, 0, 5.f, false); Edge edge81 = graphModel.factory().newEdge(node8, node1, false); - undirectedGraph.addEdge(edge12); + undirectedGraph.addEdge(edge12_1); + undirectedGraph.addEdge(edge12_2); + undirectedGraph.addEdge(edge12_3); undirectedGraph.addEdge(edge23); undirectedGraph.addEdge(edge34); undirectedGraph.addEdge(edge45); undirectedGraph.addEdge(edge56); undirectedGraph.addEdge(edge67); - undirectedGraph.addEdge(edge78); + undirectedGraph.addEdge(edge78_1); + undirectedGraph.addEdge(edge78_2); undirectedGraph.addEdge(edge81); UndirectedGraph hgraph = graphModel.getUndirectedGraph();