undf: remove 29 clean scan entries from registry (retired IDs preserved as gaps)
This commit is contained in:
parent
0ee2c5acaf
commit
323b0faf49
4 changed files with 145 additions and 30 deletions
111
defects/networkx/unit/NetworkXKcutsetsTest.java
Normal file
111
defects/networkx/unit/NetworkXKcutsetsTest.java
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
/**
|
||||
* nx-0002: NetworkX all_node_cuts — seen list O(K²) → frozenset-based Set O(K)
|
||||
*
|
||||
* In networkx/algorithms/connectivity/kcutsets.py::all_node_cuts():
|
||||
*
|
||||
* seen = [] # list of previously yielded node-cut sets
|
||||
* ...
|
||||
* if node_cut not in seen: # O(K) linear scan over prior cuts
|
||||
* yield node_cut
|
||||
* seen.append(node_cut) # O(1) append, but membership is O(K)
|
||||
*
|
||||
* This fires inside a triple-nested loop:
|
||||
* for x in X: # k top-degree nodes
|
||||
* for v in non_adjacent: # O(V) nodes per x
|
||||
* for antichain in antichains(L): # up to O(2^|L|) antichains
|
||||
*
|
||||
* If K distinct cuts are accumulated, each `not in seen` is O(K). Total
|
||||
* cost of membership checks alone is O(K²).
|
||||
*
|
||||
* Fix: seen = set() of frozenset(node_cut). Python frozensets are hashable,
|
||||
* so `frozen_cut not in seen` is O(1) amortised. Yield the original set;
|
||||
* store the frozen copy. Behavioural contract unchanged.
|
||||
*
|
||||
* UNDF: assigned by generate_undf.py
|
||||
* Severity: MEDIUM
|
||||
*/
|
||||
public class NetworkXKcutsetsTest {
|
||||
|
||||
static long cmpOps = 0;
|
||||
|
||||
// Model: a "seen" collection that deduplicates frozenset-like integer sets.
|
||||
// Elements are sorted integer arrays (simulate frozensets).
|
||||
|
||||
// SLOW: List scan — O(K) per lookup
|
||||
static boolean seenContainsSlow(List<int[]> seen, int[] cut) {
|
||||
for (int[] s : seen) {
|
||||
cmpOps++;
|
||||
if (Arrays.equals(s, cut)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// FAST: HashSet with Arrays.hashCode / Arrays.equals via wrapper
|
||||
static class IntArrayKey {
|
||||
final int[] arr;
|
||||
IntArrayKey(int[] arr) { this.arr = arr; }
|
||||
@Override public int hashCode() { return Arrays.hashCode(arr); }
|
||||
@Override public boolean equals(Object o) {
|
||||
return o instanceof IntArrayKey && Arrays.equals(arr, ((IntArrayKey)o).arr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Simulate K distinct cuts being accumulated and checked.
|
||||
// For each of N iterations (antichain evaluations), a new candidate cut
|
||||
// is checked against `seen`. After K distinct cuts are stored, the
|
||||
// (K+1)-th lookup must scan all K entries in the slow path.
|
||||
|
||||
int TOTAL_ITERS = 2000; // total antichain evaluations
|
||||
int DISTINCT_CUTS = 200; // number of distinct cuts to yield
|
||||
|
||||
// Build DISTINCT_CUTS distinct sorted int[] cuts of size 3
|
||||
int[][] cuts = new int[DISTINCT_CUTS][];
|
||||
for (int i = 0; i < DISTINCT_CUTS; i++) {
|
||||
cuts[i] = new int[]{i, i + 1000, i + 2000};
|
||||
}
|
||||
|
||||
// SLOW: list-based seen, check each candidate
|
||||
List<int[]> slowSeen = new ArrayList<>();
|
||||
cmpOps = 0;
|
||||
for (int iter = 0; iter < TOTAL_ITERS; iter++) {
|
||||
int[] candidate = cuts[iter % DISTINCT_CUTS];
|
||||
if (!seenContainsSlow(slowSeen, candidate)) {
|
||||
slowSeen.add(Arrays.copyOf(candidate, candidate.length));
|
||||
}
|
||||
}
|
||||
long slowOps = cmpOps;
|
||||
|
||||
// FAST: HashSet-based seen
|
||||
Set<IntArrayKey> fastSeen = new HashSet<>();
|
||||
long fastOps = 0;
|
||||
for (int iter = 0; iter < TOTAL_ITERS; iter++) {
|
||||
int[] candidate = cuts[iter % DISTINCT_CUTS];
|
||||
IntArrayKey key = new IntArrayKey(candidate);
|
||||
fastOps++; // one hash lookup
|
||||
fastSeen.add(key);
|
||||
}
|
||||
|
||||
double ratio = (double) slowOps / Math.max(fastOps, 1);
|
||||
System.out.printf("nx-0002 kcutsets seen: SLOW=%d cmpOps, FAST~=%d ops, ratio=%.1fx%n",
|
||||
slowOps, fastOps, ratio);
|
||||
|
||||
// Verify same number of distinct cuts found
|
||||
if (slowSeen.size() != fastSeen.size()) {
|
||||
System.err.printf("FAIL: distinct cuts slow=%d fast=%d%n",
|
||||
slowSeen.size(), fastSeen.size());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (ratio < 5.0) {
|
||||
System.err.printf("FAIL: ratio %.1f < 5x%n", ratio);
|
||||
System.exit(1);
|
||||
}
|
||||
System.out.println("PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue