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

Commit 8abb4c1

Browse files
refactor(graph-utils): extract subset-aware IndexedGraph ctor; dedupe in WienerIndexCalculator
WienerIndexCalculator carried its own private `buildAdjacency(n, idxMap)` helper that materialised int[][] adjacency over a single component using exactly the same `List<Integer>[] -> int[][]` pattern already in use by NodeCentralityAnalyzer, RandomWalkAnalyzer, GraphIsomorphismChecker, and GraphUtils.IndexedGraph itself. The duplication was an attractor for bugs (any future change to the adjacency representation has to be made in N places) and obscured the fact that WienerIndexCalculator's "build indexed adjacency over the largest component" step is just an instance of the general "indexed view restricted to a vertex subset" operation. Changes: * GraphUtils.IndexedGraph: add a second constructor that takes a Collection<String> vertex subset and only includes edges with both endpoints in the subset. Vertex order is preserved from the collection's iteration order so callers can rely on stable integer indices (matches what WienerIndexCalculator was doing manually). * WienerIndexCalculator: replace the local `buildAdjacency` helper + manual index map with a single `new GraphUtils.IndexedGraph(graph, component)` call. Net deletion: ~25 lines. No behaviour change. Verified with mvn -q -DskipTests compile (exit 0) and a smoke test asserting Wiener(P5)=20, Wiener(K4)=6, Wiener(empty)=0 all match pre-refactor values.
1 parent bb6574e commit 8abb4c1

2 files changed

Lines changed: 49 additions & 28 deletions

File tree

Gvisual/src/gvisual/GraphUtils.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,48 @@ public IndexedGraph(Graph<String, Edge> graph) {
560560
}
561561
}
562562
}
563+
564+
/**
565+
* Builds an indexed representation restricted to a vertex subset.
566+
* Only edges with both endpoints in {@code vertices} are included,
567+
* and the vertex ordering is taken from {@code vertices}'s iteration
568+
* order so callers can predict integer indices.
569+
*
570+
* <p>Useful for analyzers that operate on a single component (e.g.
571+
* {@link WienerIndexCalculator}) without needing to allocate their
572+
* own private adjacency representation.</p>
573+
*
574+
* @param graph the source graph
575+
* @param vertices the vertices to include; iteration order defines indices
576+
*/
577+
public IndexedGraph(Graph<String, Edge> graph, Collection<String> vertices) {
578+
vertexList = new ArrayList<String>(vertices);
579+
n = vertexList.size();
580+
vertexIndex = new HashMap<String, Integer>(n * 2);
581+
for (int i = 0; i < n; i++) {
582+
vertexIndex.put(vertexList.get(i), i);
583+
}
584+
585+
@SuppressWarnings("unchecked")
586+
List<Integer>[] tmp = new List[n];
587+
for (int i = 0; i < n; i++) tmp[i] = new ArrayList<Integer>();
588+
for (Edge e : graph.getEdges()) {
589+
Integer ui = vertexIndex.get(e.getVertex1());
590+
Integer vi = vertexIndex.get(e.getVertex2());
591+
if (ui != null && vi != null && !ui.equals(vi)) {
592+
tmp[ui].add(vi);
593+
tmp[vi].add(ui);
594+
}
595+
}
596+
adjLists = new int[n][];
597+
for (int i = 0; i < n; i++) {
598+
List<Integer> nb = tmp[i];
599+
adjLists[i] = new int[nb.size()];
600+
for (int j = 0; j < nb.size(); j++) {
601+
adjLists[i][j] = nb.get(j);
602+
}
603+
}
604+
}
563605
}
564606

565607
// ── Betweenness Centrality (array-based Brandes) ──────────────────

Gvisual/src/gvisual/WienerIndexCalculator.java

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ public void compute() {
7676

7777
pairCount = (long) componentSize * (componentSize - 1) / 2;
7878

79-
// Build index and adjacency arrays
80-
List<String> vertices = new ArrayList<String>(component);
81-
int n = vertices.size();
82-
Map<String, Integer> idxMap = new HashMap<String, Integer>(n * 2);
83-
for (int i = 0; i < n; i++) idxMap.put(vertices.get(i), i);
84-
85-
int[][] adj = buildAdjacency(n, idxMap);
79+
// Build indexed adjacency over the largest component.
80+
// Delegates to GraphUtils.IndexedGraph to avoid duplicating the
81+
// List<Integer>[] -> int[][] build pattern (also used by
82+
// NodeCentralityAnalyzer, RandomWalkAnalyzer, etc.).
83+
GraphUtils.IndexedGraph ig = new GraphUtils.IndexedGraph(graph, component);
84+
int n = ig.n;
85+
int[][] adj = ig.adjLists;
8686

8787
// Reusable BFS structures
8888
int[] dist = new int[n];
@@ -180,27 +180,6 @@ public String getSummary() {
180180

181181
// --- Private helpers ---
182182

183-
private int[][] buildAdjacency(int n, Map<String, Integer> idxMap) {
184-
@SuppressWarnings("unchecked")
185-
List<Integer>[] tmp = new List[n];
186-
for (int i = 0; i < n; i++) tmp[i] = new ArrayList<Integer>();
187-
for (Edge e : graph.getEdges()) {
188-
Integer ui = idxMap.get(e.getVertex1());
189-
Integer vi = idxMap.get(e.getVertex2());
190-
if (ui != null && vi != null && !ui.equals(vi)) {
191-
tmp[ui].add(vi);
192-
tmp[vi].add(ui);
193-
}
194-
}
195-
int[][] adj = new int[n][];
196-
for (int i = 0; i < n; i++) {
197-
List<Integer> nb = tmp[i];
198-
adj[i] = new int[nb.size()];
199-
for (int j = 0; j < nb.size(); j++) adj[i][j] = nb.get(j);
200-
}
201-
return adj;
202-
}
203-
204183
private void ensureComputed() {
205184
if (!computed) {
206185
throw new IllegalStateException("Call compute() before querying results");

0 commit comments

Comments
 (0)