package unit; import support.BoundSetAlgorithm; import support.BoundSetAlgorithm.Result; import java.util.List; /** * Unit tests for DEFECT 0005: InferenceContext.isEquiv() List.containsAll(). * * Proves: * 1. Both implementations correctly identify equivalent and non-equivalent sets. * 2. Defective version makes exactly B*(B+1) comparisons for equal sets of size B. * 3. Fixed version makes exactly B comparisons for the same check. * 4. Doubling B quadruples defective work; doubling B doubles fixed work. * * No build tool required. Compile and run: * * cd tests * java -m jdk.compiler/com.sun.tools.javac.Main -cp . \ * support/BoundSetAlgorithm.java unit/BoundSetComplexityTest.java * java -cp . unit.BoundSetComplexityTest */ public class BoundSetComplexityTest { private static int passed = 0; private static int failed = 0; public static void main(String[] args) { System.out.println("=== BoundSetComplexityTest (DEFECT 0005) ===\n"); System.out.println("-- Correctness: equivalent and non-equivalent sets --"); testCorrectnessEquivalent(); testCorrectnessNotEquivalent(); testCorrectnessEmpty(); testCorrectnessSingleElement(); System.out.println("\n-- Complexity: defective comparison counts B*(B+1) --"); testDefectiveExactCounts(); System.out.println("\n-- Complexity: fixed comparison counts B --"); testFixedExactCounts(); System.out.println("\n-- Complexity: growth ratio proves quadratic vs linear --"); testGrowthRatio(); System.out.printf("\n%d passed, %d failed%n", passed, failed); if (failed > 0) System.exit(1); } // ─── Correctness ───────────────────────────────────────────────────────── static void testCorrectnessEquivalent() { // Forward vs reversed — same elements, different order → equivalent List b1 = BoundSetAlgorithm.buildForwardList(5); List b2 = BoundSetAlgorithm.buildReversedList(5); Result def = BoundSetAlgorithm.isEquivDefective(b1, b2); Result fix = BoundSetAlgorithm.isEquivFixed(b1, b2); assertTrue("equiv-5: defective returns true", def.equivalent); assertTrue("equiv-5: fixed returns true", fix.equivalent); } static void testCorrectnessNotEquivalent() { // [0,1,2] vs [0,1,3] — differ in one element List b1 = java.util.List.of(0, 1, 2); List b2 = java.util.List.of(0, 1, 3); Result def = BoundSetAlgorithm.isEquivDefective(new java.util.ArrayList<>(b1), new java.util.ArrayList<>(b2)); Result fix = BoundSetAlgorithm.isEquivFixed(new java.util.ArrayList<>(b1), new java.util.ArrayList<>(b2)); assertTrue("not-equiv: defective returns false", !def.equivalent); assertTrue("not-equiv: fixed returns false", !fix.equivalent); } static void testCorrectnessEmpty() { List b1 = new java.util.ArrayList<>(); List b2 = new java.util.ArrayList<>(); Result def = BoundSetAlgorithm.isEquivDefective(b1, b2); Result fix = BoundSetAlgorithm.isEquivFixed(b1, b2); assertTrue("empty: defective returns true", def.equivalent); assertTrue("empty: fixed returns true", fix.equivalent); assertEqual("empty: defective comparisons", 0L, def.comparisons); assertEqual("empty: fixed comparisons", 0L, fix.comparisons); } static void testCorrectnessSingleElement() { List b1 = java.util.List.of(42); List b2 = java.util.List.of(42); Result def = BoundSetAlgorithm.isEquivDefective(new java.util.ArrayList<>(b1), new java.util.ArrayList<>(b2)); Result fix = BoundSetAlgorithm.isEquivFixed(new java.util.ArrayList<>(b1), new java.util.ArrayList<>(b2)); assertTrue("single-42: defective returns true", def.equivalent); assertTrue("single-42: fixed returns true", fix.equivalent); // defective: b1.containsAll(b2) = 1 comparison, b2.containsAll(b1) = 1 → total 2 = B*(B+1)=1*2 assertEqual("single-42: defective comparisons", 2L, def.comparisons); // fixed: 1 element in set1 → 1 comparison assertEqual("single-42: fixed comparisons", 1L, fix.comparisons); } // ─── Exact comparison counts ────────────────────────────────────────────── /** * PROVES DEFECT: checking two equal B-element sets (forward vs reversed) * forces exactly B*(B+1) comparisons. * * Derivation (b1=[0..B-1], b2=[B-1..0]): * b1.containsAll(b2): b2[0]=B-1 found at b1[B-1] → B comparisons; * b2[1]=B-2 found at b1[B-2] → B-1 comparisons; ... * Total = B + (B-1) + ... + 1 = B*(B+1)/2. * b2.containsAll(b1): symmetric = B*(B+1)/2. * Both execute because sets are equal (|| short-circuits only on false). * Grand total: B*(B+1). */ static void testDefectiveExactCounts() { System.out.println("[defective] isEquiv(forward, reversed, B) — expected B*(B+1):"); int[] sizes = {5, 10, 20, 50, 100}; for (int b : sizes) { List b1 = BoundSetAlgorithm.buildForwardList(b); List b2 = BoundSetAlgorithm.buildReversedList(b); Result r = BoundSetAlgorithm.isEquivDefective(b1, b2); long expected = (long) b * (b + 1); System.out.printf(" B=%-4d actual=%-8d expected=%-8d %s%n", b, r.comparisons, expected, r.comparisons == expected ? "PASS" : "FAIL expected=" + expected); assertEqual("defective B=" + b, expected, r.comparisons); } } /** * PROVES FIX: checking two equal B-element sets via Set.equals() requires * exactly B comparisons — one per element in the iteration. */ static void testFixedExactCounts() { System.out.println("[fixed] isEquiv(forward, reversed, B) — expected B:"); int[] sizes = {5, 10, 20, 50, 100}; for (int b : sizes) { List b1 = BoundSetAlgorithm.buildForwardList(b); List b2 = BoundSetAlgorithm.buildReversedList(b); Result r = BoundSetAlgorithm.isEquivFixed(b1, b2); long expected = b; System.out.printf(" B=%-4d actual=%-8d expected=%-8d %s%n", b, r.comparisons, expected, r.comparisons == expected ? "PASS" : "FAIL"); assertEqual("fixed B=" + b, expected, r.comparisons); } } // ─── Growth ratio ───────────────────────────────────────────────────────── /** * PROVES QUADRATIC GROWTH: * Doubling B → defective comparisons quadruple (≈4x), fixed double (≈2x). * * Math: * defective(B) = B*(B+1) ≈ B² * defective(2B) = 2B*(2B+1) ≈ 4B² → ratio ≈ 4 * fixed(B) = B, fixed(2B) = 2B → ratio = 2 (exact) */ static void testGrowthRatio() { int[][] pairs = {{10, 20}, {20, 40}, {50, 100}, {100, 200}}; for (int[] pair : pairs) { int b1 = pair[0], b2 = pair[1]; long def1 = BoundSetAlgorithm.isEquivDefective( BoundSetAlgorithm.buildForwardList(b1), BoundSetAlgorithm.buildReversedList(b1)).comparisons; long def2 = BoundSetAlgorithm.isEquivDefective( BoundSetAlgorithm.buildForwardList(b2), BoundSetAlgorithm.buildReversedList(b2)).comparisons; long fix1 = BoundSetAlgorithm.isEquivFixed( BoundSetAlgorithm.buildForwardList(b1), BoundSetAlgorithm.buildReversedList(b1)).comparisons; long fix2 = BoundSetAlgorithm.isEquivFixed( BoundSetAlgorithm.buildForwardList(b2), BoundSetAlgorithm.buildReversedList(b2)).comparisons; double defRatio = (double) def2 / def1; double fixRatio = (double) fix2 / fix1; System.out.printf(" B %d→%d: defective ratio=%.2f (expect ~4.0) fixed ratio=%.2f (expect 2.0)%n", b1, b2, defRatio, fixRatio); assertTrue("defective B=" + b1 + "→" + b2 + " ratio ≥ 3.8", defRatio >= 3.8); assertTrue("defective B=" + b1 + "→" + b2 + " ratio ≤ 4.2", defRatio <= 4.2); assertTrue("fixed B=" + b1 + "→" + b2 + " ratio = 2.0", fixRatio == 2.0); } } // ─── Helpers ───────────────────────────────────────────────────────────── static void assertEqual(String name, long expected, long actual) { if (expected == actual) { System.out.printf(" PASS %s%n", name); passed++; } else { System.out.printf(" FAIL %s expected=%d actual=%d%n", name, expected, actual); failed++; } } static void assertTrue(String name, boolean condition) { if (condition) { System.out.printf(" PASS %s%n", name); passed++; } else { System.out.printf(" FAIL %s%n", name); failed++; } } }