forked from jgrapht/jgrapht
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Edge betweenness centrality + Girvan-Newman community detection (jgra…
…pht#1032) * Added basic implementation of edge betweenness centrality * [wip] Added two simple tests * Fixed bug with integer division * Added edge betweenness only from a subset of the vertices * Added test for weighted case in EdgeBetweennessCentrality * Added the Girvan-Newman clustering algorithm
- Loading branch information
Showing
5 changed files
with
840 additions
and
0 deletions.
There are no files selected for viewing
140 changes: 140 additions & 0 deletions
140
jgrapht-core/src/main/java/org/jgrapht/alg/clustering/GirvanNewmanClustering.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* (C) Copyright 2021-2021, by Dimitrios Michail and Contributors. | ||
* | ||
* JGraphT : a free Java graph-theory library | ||
* | ||
* See the CONTRIBUTORS.md file distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the | ||
* GNU Lesser General Public License v2.1 or later | ||
* which is available at | ||
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later | ||
*/ | ||
package org.jgrapht.alg.clustering; | ||
|
||
import java.util.List; | ||
import java.util.Map.Entry; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
import org.jgrapht.Graph; | ||
import org.jgrapht.alg.connectivity.ConnectivityInspector; | ||
import org.jgrapht.alg.interfaces.ClusteringAlgorithm; | ||
import org.jgrapht.alg.scoring.EdgeBetweennessCentrality; | ||
import org.jgrapht.alg.scoring.EdgeBetweennessCentrality.OverflowStrategy; | ||
import org.jgrapht.graph.DefaultEdge; | ||
import org.jgrapht.graph.builder.GraphTypeBuilder; | ||
import org.jgrapht.util.SupplierUtil; | ||
|
||
/** | ||
* The Girvan-Newman clustering algorithm. | ||
* | ||
* <p> | ||
* The algorithm is described in: Girvan, Michelle, and Mark EJ Newman. "Community structure in | ||
* social and biological networks." Proceedings of the national academy of sciences 99.12 (2002): | ||
* 7821-7826. | ||
* | ||
* <p> | ||
* Running time is $O(m^2 n)$ or $O(m^2n + m n^2 \log n)$ for weighted graphs. | ||
* | ||
* @author Dimitrios Michail | ||
* | ||
* @param <V> the graph vertex type | ||
* @param <E> the graph edge type | ||
*/ | ||
public class GirvanNewmanClustering<V, E> | ||
implements | ||
ClusteringAlgorithm<V> | ||
{ | ||
private Graph<V, E> graph; | ||
private int k; | ||
private final Iterable<V> startVertices; | ||
private final OverflowStrategy overflowStrategy; | ||
|
||
/** | ||
* Create a new clustering algorithm. | ||
* | ||
* @param graph the graph | ||
* @param k the desired number of clusters | ||
*/ | ||
public GirvanNewmanClustering(Graph<V, E> graph, int k) | ||
{ | ||
this(graph, k, OverflowStrategy.THROW_EXCEPTION_ON_OVERFLOW, graph.vertexSet()); | ||
} | ||
|
||
/** | ||
* Create a new clustering algorithm. | ||
* | ||
* @param graph the graph | ||
* @param k the desired number of clusters | ||
* @param overflowStrategy strategy to use if overflow is detected | ||
* @param startVertices vertices from which to start shortest path computations when computing | ||
* edge centralities. This parameter allows the user to compute edge centrality | ||
* contributions only from a subset of the vertices of the graph. If null the whole graph | ||
* vertex set is used. | ||
*/ | ||
public GirvanNewmanClustering( | ||
Graph<V, E> graph, int k, OverflowStrategy overflowStrategy, Iterable<V> startVertices) | ||
{ | ||
this.graph = Objects.requireNonNull(graph); | ||
if (k < 1 || k > graph.vertexSet().size()) { | ||
throw new IllegalArgumentException("Illegal number of clusters"); | ||
} | ||
this.k = k; | ||
this.overflowStrategy = overflowStrategy; | ||
if (startVertices == null) { | ||
this.startVertices = graph.vertexSet(); | ||
} else { | ||
this.startVertices = startVertices; | ||
} | ||
} | ||
|
||
@Override | ||
public Clustering<V> getClustering() | ||
{ | ||
// copy graph | ||
Graph<V, | ||
DefaultEdge> graphCopy = GraphTypeBuilder | ||
.forGraphType(graph.getType()).edgeSupplier(SupplierUtil.DEFAULT_EDGE_SUPPLIER) | ||
.vertexSupplier(graph.getVertexSupplier()).buildGraph(); | ||
for (V v : graph.iterables().vertices()) { | ||
graphCopy.addVertex(v); | ||
} | ||
for (E e : graph.iterables().edges()) { | ||
V sourceVertex = graph.getEdgeSource(e); | ||
V targetVertex = graph.getEdgeTarget(e); | ||
graphCopy.addEdge(sourceVertex, targetVertex); | ||
} | ||
|
||
// main algorithm | ||
while (true) { | ||
List<Set<V>> ccs = new ConnectivityInspector<>(graphCopy).connectedSets(); | ||
if (ccs.size() == k) { | ||
return new ClusteringImpl<>(ccs); | ||
} | ||
|
||
// compute edge centralities | ||
EdgeBetweennessCentrality<V, DefaultEdge> bc = | ||
new EdgeBetweennessCentrality<>(graphCopy, overflowStrategy, startVertices); | ||
|
||
// find edge with max centrality | ||
DefaultEdge maxEdge = null; | ||
double maxCentrality = 0d; | ||
for (Entry<DefaultEdge, Double> entry : bc.getScores().entrySet()) { | ||
if (Double.compare(entry.getValue(), maxCentrality) > 0 || maxEdge == null) { | ||
maxEdge = entry.getKey(); | ||
maxCentrality = entry.getValue(); | ||
} | ||
} | ||
|
||
// remove edge with max centrality | ||
graphCopy.removeEdge(maxEdge); | ||
} | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
jgrapht-core/src/main/java/org/jgrapht/alg/interfaces/EdgeScoringAlgorithm.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* (C) Copyright 2020-2020, by Dimitrios Michail and Contributors. | ||
* | ||
* JGraphT : a free Java graph-theory library | ||
* | ||
* See the CONTRIBUTORS.md file distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the | ||
* GNU Lesser General Public License v2.1 or later | ||
* which is available at | ||
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later | ||
*/ | ||
package org.jgrapht.alg.interfaces; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* An interface for all algorithms which assign scores to edges of a graph. | ||
* | ||
* @param <E> the edge type | ||
* @param <D> the score type | ||
* | ||
* @author Dimitrios Michail | ||
*/ | ||
public interface EdgeScoringAlgorithm<E, D> | ||
{ | ||
|
||
/** | ||
* Get a map with the scores of all edges | ||
* | ||
* @return a map with all scores | ||
*/ | ||
Map<E, D> getScores(); | ||
|
||
/** | ||
* Get an edge score | ||
* | ||
* @param e the edge | ||
* @return the score | ||
*/ | ||
D getEdgeScore(E e); | ||
|
||
} |
Oops, something went wrong.