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

Commit de0ee59

Browse files
Add 5 documentation pages for undocumented analysis modules
New documentation pages: - network-profiler.html: GraphNetworkProfiler — 12 structural metrics, network classification (social/scale-free/small-world/random/lattice/ tree-like/core-periphery), grading system, comparison API, performance notes - chordal.html: ChordalGraphAnalyzer — MCS with bucket-queue PEO, chordality test, optimal coloring, max clique, clique tree/junction tree, fill-in computation, minimal separators, treewidth, complexity analysis - signed-graph.html: SignedGraphAnalyzer — structural balance theory (Heider/Harary/Davis), triangle census, coalition detection, frustration index (exact + heuristic), sign prediction, vertex polarization - graph-compressor.html: GraphCompressor — 5 compression strategies (structural equivalence, neighborhood similarity, degree-based, attribute-based, k-hop locality), quotient graph builder, compressibility report, CompressionResult API with bidirectional mappings - role-classifier.html: NetworkRoleClassifier — 6 structural archetypes (hub/bridge/local-hub/connector/peripheral/isolate), adaptive percentile thresholds, Brandes betweenness, importance scoring, report generation Updated index.html sidebar with new 'Advanced Analysis' section linking all 5 pages.
1 parent 5277d14 commit de0ee59

6 files changed

Lines changed: 910 additions & 0 deletions

File tree

docs/chordal.html

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Chordal Analysis — GraphVisual</title>
7+
<link rel="stylesheet" href="styles.css">
8+
</head>
9+
<body>
10+
11+
<nav class="sidebar">
12+
<a href="index.html" class="sidebar-logo">
13+
<span>📊</span>
14+
<div>
15+
<h2>GraphVisual</h2>
16+
<small>Documentation</small>
17+
</div>
18+
</a>
19+
<div class="sidebar-section">
20+
<div class="sidebar-section-title">Getting Started</div>
21+
<a href="index.html" class="sidebar-link"><span class="icon">🏠</span>Overview</a>
22+
<a href="guide.html" class="sidebar-link"><span class="icon">🚀</span>Setup Guide</a>
23+
</div>
24+
<div class="sidebar-section">
25+
<div class="sidebar-section-title">Analysis</div>
26+
<a href="network-profiler.html" class="sidebar-link"><span class="icon">🔬</span>Network Profiler</a>
27+
<a href="chordal.html" class="sidebar-link active"><span class="icon">🔺</span>Chordal Analysis</a>
28+
<a href="signed-graph.html" class="sidebar-link"><span class="icon">±</span>Signed Graphs</a>
29+
<a href="graph-compressor.html" class="sidebar-link"><span class="icon">🗜️</span>Graph Compressor</a>
30+
<a href="role-classifier.html" class="sidebar-link"><span class="icon">🎭</span>Role Classifier</a>
31+
</div>
32+
<div class="sidebar-section">
33+
<div class="sidebar-section-title">Reference</div>
34+
<a href="api.html" class="sidebar-link"><span class="icon">📖</span>API Reference</a>
35+
<a href="cookbook.html" class="sidebar-link"><span class="icon">🍳</span>Cookbook</a>
36+
</div>
37+
</nav>
38+
39+
<div class="main">
40+
<div class="content">
41+
42+
<h1>🔺 Chordal Graph Analysis
43+
<span class="subtitle">Perfect elimination, optimal coloring, clique trees, and fill-in computation</span>
44+
</h1>
45+
46+
<p><code>ChordalGraphAnalyzer</code> determines whether a graph is <strong>chordal</strong> (triangulated) — meaning every cycle of length ≥ 4 has a chord — and exploits chordal structure for linear-time optimal solutions to problems that are NP-hard on general graphs.</p>
47+
48+
<h2>Why Chordal Graphs Matter</h2>
49+
50+
<p>Chordal graphs form the sweet spot of graph theory: complex enough to model real problems, but structured enough that normally hard problems become polynomial. When a graph is chordal:</p>
51+
52+
<ul>
53+
<li><strong>Optimal coloring</strong> — O(V+E) via greedy on reverse PEO (no backtracking needed)</li>
54+
<li><strong>Maximum clique</strong> — O(V+E) from PEO neighborhoods (NP-hard in general)</li>
55+
<li><strong>Minimum clique cover</strong> — equals chromatic number (perfect graph property)</li>
56+
<li><strong>Maximum independent set</strong> — equals clique cover number</li>
57+
<li><strong>Treewidth</strong> — directly computed as max clique size − 1</li>
58+
</ul>
59+
60+
<h2>Quick Start</h2>
61+
62+
<pre><code>// Full analysis in one call
63+
ChordalReport report = ChordalGraphAnalyzer.analyze(graph);
64+
65+
System.out.println("Chordal: " + report.getChordality().isChordal());
66+
System.out.println("Chromatic number: " + report.getColoring().getChromaticNumber());
67+
System.out.println("Max clique size: " + report.getMaxClique().size());
68+
System.out.println("Treewidth: " + ChordalGraphAnalyzer.treewidth(graph));
69+
System.out.println(report.toTextReport());</code></pre>
70+
71+
<h2>Core Algorithms</h2>
72+
73+
<h3>Maximum Cardinality Search (MCS)</h3>
74+
75+
<p>The foundation of all chordal analyses. MCS produces a vertex ordering where each vertex is selected to maximize the number of already-selected neighbors. On chordal graphs, this is a <strong>Perfect Elimination Ordering</strong> (PEO).</p>
76+
77+
<pre><code>List&lt;String&gt; peo = ChordalGraphAnalyzer.maximumCardinalitySearch(graph);</code></pre>
78+
79+
<p>Implementation uses a <strong>bucket-based priority queue</strong> for O(V+E) total time, instead of the naïve O(V²) linear scan. Each vertex lives in a bucket keyed by its current weight; selecting the maximum and incrementing neighbors are both O(1) amortized.</p>
80+
81+
<h3>Chordality Test</h3>
82+
83+
<pre><code>ChordalityResult result = ChordalGraphAnalyzer.testChordality(graph);
84+
if (result.isChordal()) {
85+
System.out.println("PEO: " + result.getPeo());
86+
} else {
87+
System.out.println("Chordless cycle: " + result.getChordlessCycle());
88+
}</code></pre>
89+
90+
<p>Verifies the MCS ordering is a valid PEO by checking that each vertex's later neighbors form a clique. If not, returns a chordless cycle of length ≥ 4 as a certificate of non-chordality.</p>
91+
92+
<h3>Optimal Coloring</h3>
93+
94+
<pre><code>ColoringResult coloring = ChordalGraphAnalyzer.optimalColoring(graph);
95+
System.out.println("χ(G) = " + coloring.getChromaticNumber());
96+
System.out.println("Assignment: " + coloring.getColors());</code></pre>
97+
98+
<p>Greedy coloring on the reverse PEO is guaranteed to use exactly χ(G) colors when the graph is chordal.</p>
99+
100+
<h3>Maximum Clique &amp; All Maximal Cliques</h3>
101+
102+
<pre><code>Set&lt;String&gt; maxClique = ChordalGraphAnalyzer.maximumClique(graph);
103+
104+
List&lt;Set&lt;String&gt;&gt; allCliques = ChordalGraphAnalyzer.allMaximalCliques(graph);
105+
System.out.println("Found " + allCliques.size() + " maximal cliques");</code></pre>
106+
107+
<h3>Clique Tree (Junction Tree)</h3>
108+
109+
<pre><code>List&lt;CliqueTreeNode&gt; tree = ChordalGraphAnalyzer.buildCliqueTree(graph);
110+
for (CliqueTreeNode node : tree) {
111+
System.out.printf("Node %d: %s → neighbors %s%n",
112+
node.getId(), node.getVertices(), node.getNeighbors());
113+
}</code></pre>
114+
115+
<p>Builds a maximum spanning tree of the clique intersection graph using Prim's algorithm. The clique tree satisfies the <strong>running intersection property</strong>: for any vertex v, the clique-tree nodes containing v form a connected subtree.</p>
116+
117+
<h3>Fill-In Computation</h3>
118+
119+
<pre><code>FillInResult fill = ChordalGraphAnalyzer.computeFillIn(graph);
120+
System.out.println("Edges needed for chordal completion: " + fill.getFillCount());
121+
for (String[] edge : fill.getFillEdges()) {
122+
System.out.println(" " + edge[0] + " — " + edge[1]);
123+
}</code></pre>
124+
125+
<h3>Minimal Separators &amp; Treewidth</h3>
126+
127+
<pre><code>List&lt;Set&lt;String&gt;&gt; separators = ChordalGraphAnalyzer.minimalSeparators(graph);
128+
int tw = ChordalGraphAnalyzer.treewidth(graph); // max clique size − 1</code></pre>
129+
130+
<h2>Performance</h2>
131+
132+
<p>The <code>analyze()</code> method computes all results in a single pass, sharing the MCS ordering, adjacency map, and position map across all sub-analyses. Before this optimization, calling individual methods (coloring, max clique, clique tree, etc.) would each independently re-run MCS — resulting in 5× redundant O(V+E) traversals.</p>
133+
134+
<table>
135+
<thead>
136+
<tr><th>Operation</th><th>Complexity</th></tr>
137+
</thead>
138+
<tbody>
139+
<tr><td>MCS / PEO</td><td>O(V + E)</td></tr>
140+
<tr><td>Chordality test</td><td>O(V + E)</td></tr>
141+
<tr><td>Optimal coloring</td><td>O(V + E)</td></tr>
142+
<tr><td>Maximum clique</td><td>O(V + E)</td></tr>
143+
<tr><td>All maximal cliques</td><td>O(V + E + output)</td></tr>
144+
<tr><td>Clique tree</td><td>O(k²) where k = number of maximal cliques</td></tr>
145+
<tr><td>Fill-in</td><td>O(V · Δ²) where Δ = max later-neighborhood size</td></tr>
146+
<tr><td>Full <code>analyze()</code></td><td>O(V + E + k²)</td></tr>
147+
</tbody>
148+
</table>
149+
150+
<h2>API Reference</h2>
151+
152+
<table>
153+
<thead>
154+
<tr><th>Method</th><th>Returns</th><th>Description</th></tr>
155+
</thead>
156+
<tbody>
157+
<tr><td><code>analyze(graph)</code></td><td><code>ChordalReport</code></td><td>Full analysis — chordality, coloring, cliques, tree, fill-in</td></tr>
158+
<tr><td><code>testChordality(graph)</code></td><td><code>ChordalityResult</code></td><td>Test chordality, get PEO or chordless cycle</td></tr>
159+
<tr><td><code>maximumCardinalitySearch(graph)</code></td><td><code>List&lt;String&gt;</code></td><td>Bucket-queue MCS ordering</td></tr>
160+
<tr><td><code>optimalColoring(graph)</code></td><td><code>ColoringResult</code></td><td>Minimum coloring via reverse PEO</td></tr>
161+
<tr><td><code>maximumClique(graph)</code></td><td><code>Set&lt;String&gt;</code></td><td>Largest clique (exact for chordal, greedy otherwise)</td></tr>
162+
<tr><td><code>allMaximalCliques(graph)</code></td><td><code>List&lt;Set&lt;String&gt;&gt;</code></td><td>Enumerate all maximal cliques</td></tr>
163+
<tr><td><code>buildCliqueTree(graph)</code></td><td><code>List&lt;CliqueTreeNode&gt;</code></td><td>Junction tree decomposition</td></tr>
164+
<tr><td><code>computeFillIn(graph)</code></td><td><code>FillInResult</code></td><td>Minimum edges for chordal completion</td></tr>
165+
<tr><td><code>minimalSeparators(graph)</code></td><td><code>List&lt;Set&lt;String&gt;&gt;</code></td><td>All minimal vertex separators</td></tr>
166+
<tr><td><code>treewidth(graph)</code></td><td><code>int</code></td><td>Treewidth = max clique size − 1</td></tr>
167+
<tr><td><code>eliminationCliques(graph, order)</code></td><td><code>List&lt;Set&lt;String&gt;&gt;</code></td><td>Cliques formed at each elimination step</td></tr>
168+
</tbody>
169+
</table>
170+
171+
</div>
172+
</div>
173+
174+
</body>
175+
</html>

docs/graph-compressor.html

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Graph Compressor — GraphVisual</title>
7+
<link rel="stylesheet" href="styles.css">
8+
</head>
9+
<body>
10+
11+
<nav class="sidebar">
12+
<a href="index.html" class="sidebar-logo">
13+
<span>📊</span>
14+
<div>
15+
<h2>GraphVisual</h2>
16+
<small>Documentation</small>
17+
</div>
18+
</a>
19+
<div class="sidebar-section">
20+
<div class="sidebar-section-title">Getting Started</div>
21+
<a href="index.html" class="sidebar-link"><span class="icon">🏠</span>Overview</a>
22+
<a href="guide.html" class="sidebar-link"><span class="icon">🚀</span>Setup Guide</a>
23+
</div>
24+
<div class="sidebar-section">
25+
<div class="sidebar-section-title">Analysis</div>
26+
<a href="network-profiler.html" class="sidebar-link"><span class="icon">🔬</span>Network Profiler</a>
27+
<a href="chordal.html" class="sidebar-link"><span class="icon">🔺</span>Chordal Analysis</a>
28+
<a href="signed-graph.html" class="sidebar-link"><span class="icon">±</span>Signed Graphs</a>
29+
<a href="graph-compressor.html" class="sidebar-link active"><span class="icon">🗜️</span>Graph Compressor</a>
30+
<a href="role-classifier.html" class="sidebar-link"><span class="icon">🎭</span>Role Classifier</a>
31+
</div>
32+
<div class="sidebar-section">
33+
<div class="sidebar-section-title">Reference</div>
34+
<a href="api.html" class="sidebar-link"><span class="icon">📖</span>API Reference</a>
35+
<a href="cookbook.html" class="sidebar-link"><span class="icon">🍳</span>Cookbook</a>
36+
</div>
37+
</nav>
38+
39+
<div class="main">
40+
<div class="content">
41+
42+
<h1>🗜️ Graph Compressor
43+
<span class="subtitle">Quotient graphs via structural equivalence, similarity, degree, attributes, and k-hop locality</span>
44+
</h1>
45+
46+
<p><code>GraphCompressor</code> reduces a graph by merging groups of nodes into <strong>supernodes</strong>, producing a smaller <strong>quotient graph</strong> that preserves the macro-structure of the original network. Useful for visualization of large graphs, summarization, and multi-scale analysis.</p>
47+
48+
<h2>Compression Strategies</h2>
49+
50+
<div class="card-grid">
51+
<div class="card">
52+
<div class="icon">🔗</div>
53+
<h4>Structural Equivalence</h4>
54+
<p>Merges nodes with identical neighbor sets. Two nodes are structurally equivalent if they connect to exactly the same set of other nodes.</p>
55+
</div>
56+
<div class="card">
57+
<div class="icon">📏</div>
58+
<h4>Neighborhood Similarity</h4>
59+
<p>Relaxed equivalence — merges nodes whose neighbor sets have Jaccard similarity above a threshold. Tunable from strict (1.0) to aggressive (0.3).</p>
60+
</div>
61+
<div class="card">
62+
<div class="icon">📊</div>
63+
<h4>Degree-Based</h4>
64+
<p>Groups nodes by degree (exact or binned ranges). Useful for degree-preserving summaries.</p>
65+
</div>
66+
<div class="card">
67+
<div class="icon">🏷️</div>
68+
<h4>Attribute-Based</h4>
69+
<p>Groups nodes by any user-supplied function — community label, node type, geographic region, etc.</p>
70+
</div>
71+
<div class="card">
72+
<div class="icon">🎯</div>
73+
<h4>K-Hop Locality</h4>
74+
<p>Each seed node absorbs its k-hop neighborhood into a supernode. Creates region-based summaries centered on key vertices.</p>
75+
</div>
76+
</div>
77+
78+
<h2>Quick Start</h2>
79+
80+
<pre><code>GraphCompressor compressor = new GraphCompressor(graph);
81+
82+
// Structural equivalence
83+
CompressionResult result = compressor.byStructuralEquivalence();
84+
System.out.println(result.getSummary());
85+
86+
// Neighborhood similarity (50% overlap)
87+
CompressionResult sim = compressor.byNeighborhoodSimilarity(0.5);
88+
89+
// Degree-based with bin size 5
90+
CompressionResult deg = compressor.byDegree(5);
91+
92+
// Attribute-based (e.g., by community label)
93+
Map&lt;String, String&gt; communities = Map.of("A", "comm1", "B", "comm1", "C", "comm2");
94+
CompressionResult attr = compressor.byAttribute(communities::get);
95+
96+
// K-hop locality (2 hops around seed nodes)
97+
CompressionResult khop = compressor.byKHopLocality(List.of("hub1", "hub2"), 2);
98+
99+
// Access the compressed graph
100+
Graph&lt;String, Edge&gt; quotient = result.getCompressedGraph();</code></pre>
101+
102+
<h2>Compression Result</h2>
103+
104+
<p>Every strategy returns a <code>CompressionResult</code> with rich statistics and bidirectional mappings:</p>
105+
106+
<pre><code>=== Graph Compression Result ===
107+
Strategy: structural_equivalence
108+
Original: 500 nodes, 2340 edges
109+
Compressed: 42 nodes, 186 edges
110+
Node reduction: 91.6%
111+
Edge reduction: 92.1%
112+
Compression ratio: 0.084
113+
Merged groups: 38
114+
Largest supernode: 24 members
115+
Avg supernode size: 11.9</code></pre>
116+
117+
<table>
118+
<thead>
119+
<tr><th>Method</th><th>Description</th></tr>
120+
</thead>
121+
<tbody>
122+
<tr><td><code>getCompressedGraph()</code></td><td>The quotient JUNG graph</td></tr>
123+
<tr><td><code>getSupernodeMembers()</code></td><td>Map: supernode → list of original nodes</td></tr>
124+
<tr><td><code>getNodeToSupernode()</code></td><td>Map: original node → its supernode</td></tr>
125+
<tr><td><code>getCompressionRatio()</code></td><td>Compressed/original node ratio (lower = more compression)</td></tr>
126+
<tr><td><code>getNodeReductionPercent()</code></td><td>Percentage of nodes eliminated</td></tr>
127+
<tr><td><code>getEdgeReductionPercent()</code></td><td>Percentage of edges eliminated</td></tr>
128+
<tr><td><code>getLargestSupernodeSize()</code></td><td>Number of nodes in the biggest supernode</td></tr>
129+
<tr><td><code>getMembersOf(supernodeId)</code></td><td>Look up members of a specific supernode</td></tr>
130+
<tr><td><code>getSupernodeOf(nodeId)</code></td><td>Find which supernode an original node belongs to</td></tr>
131+
<tr><td><code>toCSV()</code></td><td>Export mapping as CSV (original_node, supernode, group_size)</td></tr>
132+
<tr><td><code>getSummary()</code></td><td>Human-readable compression summary</td></tr>
133+
</tbody>
134+
</table>
135+
136+
<h2>Compressibility Report</h2>
137+
138+
<p>Compare all strategies at once to find the best compression approach:</p>
139+
140+
<pre><code>String report = compressor.compressibilityReport();
141+
System.out.println(report);</code></pre>
142+
143+
<pre><code>=== Graph Compressibility Report ===
144+
Original: 500 nodes, 2340 edges
145+
146+
Structural Equivalence → 42 supernodes, 186 edges (91.6% node reduction, 92.1% edge reduction)
147+
Neighborhood Sim (t=0.9) → 68 supernodes, 312 edges (86.4% node reduction, 86.7% edge reduction)
148+
Neighborhood Sim (t=0.7) → 35 supernodes, 148 edges (93.0% node reduction, 93.7% edge reduction)
149+
Neighborhood Sim (t=0.5) → 21 supernodes, 89 edges (95.8% node reduction, 96.2% edge reduction)
150+
Neighborhood Sim (t=0.3) → 12 supernodes, 41 edges (97.6% node reduction, 98.2% edge reduction)
151+
Exact Degree → 28 supernodes, 1102 edges (94.4% node reduction, 52.9% edge reduction)
152+
Degree (bin=2) → 14 supernodes, 572 edges (97.2% node reduction, 75.6% edge reduction)
153+
Degree (bin=5) → 8 supernodes, 234 edges (98.4% node reduction, 90.0% edge reduction)
154+
Degree (bin=10) → 5 supernodes, 112 edges (99.0% node reduction, 95.2% edge reduction)</code></pre>
155+
156+
<h2>Performance Notes</h2>
157+
158+
<ul>
159+
<li><strong>Neighborhood similarity</strong> uses degree-sorted vertex ordering + upper-bound pruning: if min(|A|,|B|)/max(|A|,|B|) < threshold, the inner loop breaks early (no vertex with higher degree can match).</li>
160+
<li><strong>Jaccard computation</strong> avoids HashSet allocation — iterates the smaller set and checks membership in the larger set directly.</li>
161+
<li><strong>Superedge aggregation</strong> tracks edge count and total weight per supernode pair.</li>
162+
</ul>
163+
164+
</div>
165+
</div>
166+
167+
</body>
168+
</html>

docs/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ <h2>GraphVisual</h2>
6262
<a href="gnn-playground.html" class="sidebar-link"><span class="icon">🧠</span>GNN Playground</a>
6363
<a href="narrative.html" class="sidebar-link"><span class="icon">📝</span>Narrative Gen</a>
6464
</div>
65+
<div class="sidebar-section">
66+
<div class="sidebar-section-title">Advanced Analysis</div>
67+
<a href="network-profiler.html" class="sidebar-link"><span class="icon">🔬</span>Network Profiler</a>
68+
<a href="chordal.html" class="sidebar-link"><span class="icon">🔺</span>Chordal Analysis</a>
69+
<a href="signed-graph.html" class="sidebar-link"><span class="icon">±</span>Signed Graphs</a>
70+
<a href="graph-compressor.html" class="sidebar-link"><span class="icon">🗜️</span>Graph Compressor</a>
71+
<a href="role-classifier.html" class="sidebar-link"><span class="icon">🎭</span>Role Classifier</a>
72+
</div>
6573
<div class="sidebar-section">
6674
<div class="sidebar-section-title">Architecture</div>
6775
<a href="architecture.html" class="sidebar-link"><span class="icon">🏗️</span>Architecture</a>

0 commit comments

Comments
 (0)