java-topology/defects/bird/unit/BirdCommunitySetAlgorithmTest.java

153 lines
5.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.*;
/**
* Models BIRD routing daemon community set operations.
*
* bird-0003: int_set_union O(N×M) — contains check in union loop
* bird-0004: clist_filter O(L×S) — contains check in filter loop
*
* SLOW: O(N×M) union / O(L×S) filter — linear scan per element
* FAST: O(N+M) union / O(L+S) filter — HashSet pre-built from second operand
*
* CWE-407: nest/a-set.c:394 (union), filter/data.c:421 (filter)
*/
public class BirdCommunitySetAlgorithmTest {
// -------------------------------------------------------------------------
// Slow (defective) — mirrors int_set_contains in loop
// -------------------------------------------------------------------------
static class SlowCommunityOps {
long scanOps = 0;
boolean contains(int[] arr, int val) {
for (int v : arr) {
scanOps++;
if (v == val) return true;
}
return false;
}
/** bird-0003: O(N×M) union */
int[] union(int[] l1, int[] l2) {
List<Integer> result = new ArrayList<>();
for (int v : l1) result.add(v);
for (int v : l2) {
if (!contains(l1, v)) result.add(v);
}
return result.stream().mapToInt(Integer::intValue).toArray();
}
/** bird-0004: O(L×S) filter — keep entries in l1 that are in filterSet */
int[] filter(int[] l1, int[] filterSet) {
List<Integer> result = new ArrayList<>();
for (int v : l1) {
if (contains(filterSet, v)) result.add(v);
}
return result.stream().mapToInt(Integer::intValue).toArray();
}
long unionOps(int[] l1, int[] l2) { scanOps = 0; union(l1, l2); return scanOps; }
long filterOps(int[] l1, int[] filterSet) { scanOps = 0; filter(l1, filterSet); return scanOps; }
}
// -------------------------------------------------------------------------
// Fast (fixed) — HashSet from one operand
// -------------------------------------------------------------------------
static class FastCommunityOps {
long scanOps = 0;
int[] union(int[] l1, int[] l2) {
Set<Integer> seen = new HashSet<>();
for (int v : l1) { seen.add(v); scanOps++; }
List<Integer> result = new ArrayList<>(Arrays.stream(l1).boxed().toList());
for (int v : l2) {
scanOps++;
if (seen.add(v)) result.add(v);
}
return result.stream().mapToInt(Integer::intValue).toArray();
}
int[] filter(int[] l1, int[] filterSet) {
Set<Integer> fs = new HashSet<>();
for (int v : filterSet) { fs.add(v); scanOps++; }
List<Integer> result = new ArrayList<>();
for (int v : l1) {
scanOps++;
if (fs.contains(v)) result.add(v);
}
return result.stream().mapToInt(Integer::intValue).toArray();
}
long unionOps(int[] l1, int[] l2) { scanOps = 0; union(l1, l2); return scanOps; }
long filterOps(int[] l1, int[] filterSet) { scanOps = 0; filter(l1, filterSet); return scanOps; }
}
static int[] range(int from, int n) {
int[] a = new int[n];
for (int i = 0; i < n; i++) a[i] = from + i;
return a;
}
public static void main(String[] args) {
SlowCommunityOps slow = new SlowCommunityOps();
FastCommunityOps fast = new FastCommunityOps();
int passed = 0, total = 0;
System.out.println("=== bird-0003: int_set_union O(N×M) ===");
int[] sizes = {50, 100, 200, 500};
for (int n : sizes) {
int[] l1 = range(0, n);
int[] l2 = range(n / 2, n); // partial overlap
long s = slow.unionOps(l1, l2);
long f = fast.unionOps(l1, l2);
double ratio = (double) s / f;
total++;
boolean ok = s > f && ratio >= 5.0;
System.out.printf("N=%3d slow=%8d fast=%5d ratio=%6.1fx %s%n",
n, s, f, ratio, ok ? "PASS" : "FAIL");
if (ok) passed++;
}
System.out.println("=== bird-0004: clist_filter O(L×S) ===");
for (int n : sizes) {
int[] l1 = range(0, n); // route's community list
int[] filterSet = range(n/4, n/2); // keep middle half
long s = slow.filterOps(l1, filterSet);
long f = fast.filterOps(l1, filterSet);
double ratio = (double) s / f;
total++;
boolean ok = s > f && ratio >= 3.0;
System.out.printf("L=%3d S=%3d slow=%8d fast=%5d ratio=%6.1fx %s%n",
n, n/2, s, f, ratio, ok ? "PASS" : "FAIL");
if (ok) passed++;
}
// Correctness: union contains all unique elements
int[] a = range(0, 100), b = range(50, 100);
int[] slowUnion = slow.union(a, b);
int[] fastUnion = fast.union(a, b);
Arrays.sort(slowUnion); Arrays.sort(fastUnion);
total++;
boolean correct1 = Arrays.equals(slowUnion, fastUnion);
System.out.printf("union correctness: %s%n", correct1 ? "PASS" : "FAIL");
if (correct1) passed++;
// Correctness: filter returns same kept elements
int[] l = range(0, 100), fs = range(20, 60);
int[] slowFilter = slow.filter(l, fs);
int[] fastFilter = fast.filter(l, fs);
Arrays.sort(slowFilter); Arrays.sort(fastFilter);
total++;
boolean correct2 = Arrays.equals(slowFilter, fastFilter);
System.out.printf("filter correctness: %s%n", correct2 ? "PASS" : "FAIL");
if (correct2) passed++;
System.out.printf("%n%d/%d PASS%n", passed, total);
if (passed < total) System.exit(1);
}
}