wave8a: 436/195 — istio-0002, spark-0002, igraph-0001 + PDF

This commit is contained in:
russell@unturf.com 2026-03-27 16:31:34 -04:00
parent 5fe6da7cc2
commit 2d3e3d603e
7 changed files with 508 additions and 5 deletions

View file

@ -0,0 +1,187 @@
package unit;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* IgraphCohesiveBlocksTest
*
* Models CWE-407 defect igraph-0001:
*
* python-igraph CohesiveBlocks.max_cohesion() list membership scan
* File: src/igraph/clustering.py, line 1311
*
* Defective: self._clusters is a list-of-lists; `if idx in cluster` is
* O(|cluster|) per block, O(B×C) per call, O(V×B×C) for all
* vertices degrades to O(V²) when B×C ~ V.
*
* Fixed: self._cluster_sets is a list-of-frozensets; `if idx in
* cluster_set` is O(1); full-pass cost is O(V×B).
*
* Tests instrument comparison counts explicitly no wall-clock timing.
*/
public class IgraphCohesiveBlocksTest {
// -----------------------------------------------------------------------
// Model: a CohesiveBlocks object with B blocks, each of size C.
// Vertex indices are integers 0..V-1.
// We simulate max_cohesion(idx) for each vertex 0..V-1.
// -----------------------------------------------------------------------
/**
* Defective path: each cluster stored as ArrayList.
* `if idx in cluster` performs a linear scan of the list.
*
* @param numVertices V total vertex count
* @param numBlocks B number of cohesive blocks
* @param clusterSize C vertices per block (each block = consecutive V IDs)
* @return total element comparisons across all V calls to max_cohesion
*/
static long defectiveMaxCohesion(int numVertices, int numBlocks, int clusterSize) {
// Build B clusters, each containing clusterSize consecutive vertex IDs
// (wrapping mod V to keep IDs in range)
List<ArrayList<Integer>> clusters = new ArrayList<>();
int[] cohesion = new int[numBlocks];
for (int b = 0; b < numBlocks; b++) {
ArrayList<Integer> cluster = new ArrayList<>();
for (int c = 0; c < clusterSize; c++) {
cluster.add((b * clusterSize + c) % numVertices);
}
clusters.add(cluster);
cohesion[b] = b + 1; // arbitrary cohesion score
}
long comparisons = 0;
// Simulate max_cohesion(idx) for every vertex (the natural full-pass use)
for (int idx = 0; idx < numVertices; idx++) {
// Defective: for each block, scan the list linearly
for (int b = 0; b < numBlocks; b++) {
ArrayList<Integer> cluster = clusters.get(b);
for (Integer member : cluster) {
comparisons++; // O(|cluster|) list scan
if (member.equals(idx)) {
break; // found stop scanning this cluster
}
}
}
}
return comparisons;
}
/**
* Fixed path: each cluster stored as HashSet (models Python frozenset).
* `if idx in cluster_set` is O(1) average.
*
* @param numVertices V
* @param numBlocks B
* @param clusterSize C
* @return total hash lookups across all V calls to max_cohesion
*/
static long fixedMaxCohesion(int numVertices, int numBlocks, int clusterSize) {
List<HashSet<Integer>> clusterSets = new ArrayList<>();
for (int b = 0; b < numBlocks; b++) {
HashSet<Integer> set = new HashSet<>();
for (int c = 0; c < clusterSize; c++) {
set.add((b * clusterSize + c) % numVertices);
}
clusterSets.add(set);
}
long lookups = 0;
for (int idx = 0; idx < numVertices; idx++) {
for (int b = 0; b < numBlocks; b++) {
lookups++; // O(1) hash probe CWE-407 fix
clusterSets.get(b).contains(idx);
}
}
return lookups;
}
// -----------------------------------------------------------------------
// Test 1: defective cost > fixed cost at V=100, B=20, C=10
// -----------------------------------------------------------------------
static void test1_listScanCostsMoreThanSetLookup() {
int V = 100, B = 20, C = 10;
long defectOps = defectiveMaxCohesion(V, B, C);
long fixedOps = fixedMaxCohesion(V, B, C);
System.out.printf(
"test1: V=%d B=%d C=%d defect_comparisons=%d fixed_lookups=%d%n",
V, B, C, defectOps, fixedOps);
assert defectOps > fixedOps
: "igraph-0001: list scan must do more work than set lookup; defect="
+ defectOps + " fixed=" + fixedOps;
// Fixed cost is exactly V*B (one hash probe per block per vertex)
assert fixedOps == (long) V * B
: "igraph-0001: fixed lookups should be V*B=" + ((long) V * B)
+ " got " + fixedOps;
}
// -----------------------------------------------------------------------
// Test 2: defect grows super-linearly with clusterSize; fixed does not
// Doubling C doubles defect cost (more comparisons per scan),
// but fixed cost stays constant (O(1) per lookup regardless of C).
// -----------------------------------------------------------------------
static void test2_defectGrowsWithClusterSize() {
int V = 80, B = 10;
int C1 = 8, C2 = 16; // double cluster size
long d1 = defectiveMaxCohesion(V, B, C1);
long d2 = defectiveMaxCohesion(V, B, C2);
long f1 = fixedMaxCohesion(V, B, C1);
long f2 = fixedMaxCohesion(V, B, C2);
System.out.printf(
"test2: V=%d B=%d C1=%d defect=%d fixed=%d | C2=%d defect=%d fixed=%d%n",
V, B, C1, d1, f1, C2, d2, f2);
// Defect cost grows with C; fixed cost is independent of C
assert d2 > d1
: "igraph-0001: defect comparisons must grow as cluster size increases";
assert f2 == f1
: "igraph-0001: fixed lookups must not change with cluster size; f1="
+ f1 + " f2=" + f2;
}
// -----------------------------------------------------------------------
// Test 3: at large scale (V=500, B=50, C=50) defect cost is at least
// 10x the fixed cost demonstrating quadratic vs linear behaviour.
// -----------------------------------------------------------------------
static void test3_largeScaleSpeedup() {
int V = 500, B = 50, C = 50;
long defectOps = defectiveMaxCohesion(V, B, C);
long fixedOps = fixedMaxCohesion(V, B, C);
double ratio = (double) defectOps / Math.max(1, fixedOps);
System.out.printf(
"test3: V=%d B=%d C=%d defect=%d fixed=%d ratio=%.1fx%n",
V, B, C, defectOps, fixedOps, ratio);
assert ratio >= 10.0
: "igraph-0001: expected >= 10x speedup from set; got ratio=" + ratio;
}
// -----------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------
public static void main(String[] args) {
System.out.println("=== IgraphCohesiveBlocksTest ===");
System.out.println("Modelling CWE-407: igraph-0001 — CohesiveBlocks.max_cohesion list scan");
System.out.println();
test1_listScanCostsMoreThanSetLookup();
System.out.println(" PASS test1_listScanCostsMoreThanSetLookup");
test2_defectGrowsWithClusterSize();
System.out.println(" PASS test2_defectGrowsWithClusterSize");
test3_largeScaleSpeedup();
System.out.println(" PASS test3_largeScaleSpeedup");
System.out.println();
System.out.println("3/3 PASS");
}
}