Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

Commit 7d99ed3

Browse files
perf(motif): use HashSet lookups in getLocalClustering instead of graph.isNeighbor
Replace JUNG's graph.isNeighbor() calls in the local clustering coefficient computation with O(1) HashSet lookups. JUNG's isNeighbor can be O(degree) per call, making the per-vertex cost O(k^3) for high-degree nodes. The new approach builds neighbour sets on demand (or reuses them if called during analyze()), reducing per-vertex cost to O(k^2). This matches the pattern already used in findOpenPaths and findSquares.
1 parent 56c7bd1 commit 7d99ed3

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

Gvisual/src/gvisual/GraphMotifFinder.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,28 +265,48 @@ public double getClusteringCoefficient() {
265265

266266
/**
267267
* Compute per-node local clustering coefficient.
268+
*
269+
* <p>Uses O(1) HashSet lookups instead of JUNG's {@code isNeighbor()}
270+
* which can be O(degree) per call, reducing per-vertex cost from
271+
* O(k³) to O(k²).</p>
272+
*
268273
* @return map of node → local clustering coefficient
269274
*/
270275
public Map<String, Double> getLocalClustering() {
276+
// Build neighbour sets if not available (analyze() nulls them out)
277+
boolean builtLocally = false;
278+
Map<String, Set<String>> nbSets = this.neighborSets;
279+
if (nbSets == null) {
280+
builtLocally = true;
281+
nbSets = new HashMap<>(graph.getVertexCount() * 2);
282+
for (String v : graph.getVertices()) {
283+
nbSets.put(v, new HashSet<>(graph.getNeighbors(v)));
284+
}
285+
}
286+
271287
Map<String, Double> result = new LinkedHashMap<>();
272288
for (String v : graph.getVertices()) {
273-
List<String> neighbors = new ArrayList<>(graph.getNeighbors(v));
274-
int k = neighbors.size();
289+
Collection<String> rawNbrs = graph.getNeighbors(v);
290+
int k = rawNbrs.size();
275291
if (k < 2) {
276292
result.put(v, 0.0);
277293
continue;
278294
}
295+
List<String> neighbors = new ArrayList<>(rawNbrs);
279296
int links = 0;
280297
for (int i = 0; i < neighbors.size(); i++) {
298+
Set<String> iNbrs = nbSets.get(neighbors.get(i));
281299
for (int j = i + 1; j < neighbors.size(); j++) {
282-
if (graph.isNeighbor(neighbors.get(i), neighbors.get(j))) {
300+
if (iNbrs.contains(neighbors.get(j))) {
283301
links++;
284302
}
285303
}
286304
}
287305
double maxLinks = k * (k - 1.0) / 2.0;
288306
result.put(v, links / maxLinks);
289307
}
308+
309+
if (builtLocally) nbSets = null; // let GC reclaim
290310
return result;
291311
}
292312

0 commit comments

Comments
 (0)