Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
219 lines
9.7 KiB
Java
219 lines
9.7 KiB
Java
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<Integer> b1 = BoundSetAlgorithm.buildForwardList(5);
|
|
List<Integer> 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<Integer> b1 = java.util.List.of(0, 1, 2);
|
|
List<Integer> 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<Integer> b1 = new java.util.ArrayList<>();
|
|
List<Integer> 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<Integer> b1 = java.util.List.of(42);
|
|
List<Integer> 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<Integer> b1 = BoundSetAlgorithm.buildForwardList(b);
|
|
List<Integer> 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<Integer> b1 = BoundSetAlgorithm.buildForwardList(b);
|
|
List<Integer> 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++;
|
|
}
|
|
}
|
|
}
|