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.
109 lines
4.5 KiB
Java
109 lines
4.5 KiB
Java
package support;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* Reference implementations of InferenceContext.isEquiv() — defective and fixed.
|
|
*
|
|
* DEFECT 0005 (jdk.compiler, InferenceContext.java:506):
|
|
* isEquiv() uses List.containsAll() for set-equality comparison of bound lists.
|
|
* Called twice (mutual containment): !b1.containsAll(b2) || !b2.containsAll(b1).
|
|
* com.sun.tools.javac.util.List is a linked list — contains() is O(N).
|
|
*
|
|
* Fix: convert to LinkedHashSet and use Set.equals() — O(B) total.
|
|
*
|
|
* Exact comparison counts for equal sets of size B (forward vs reversed order):
|
|
* defective: B*(B+1) (two containsAll calls, each = B*(B+1)/2)
|
|
* fixed: B (one Set.equals check = B membership tests)
|
|
*
|
|
* Derivation of defective count:
|
|
* b1 = [0, 1, ..., B-1], b2 = [B-1, B-2, ..., 0] (reversed — worst order).
|
|
* b1.containsAll(b2): for each element x in b2, scan b1 until x found:
|
|
* x=B-1: scan to index B-1 → B comparisons
|
|
* x=B-2: scan to index B-2 → B-1 comparisons
|
|
* ...
|
|
* x=0: scan to index 0 → 1 comparison
|
|
* Total: B + (B-1) + ... + 1 = B*(B+1)/2.
|
|
* b2.containsAll(b1): symmetric = B*(B+1)/2.
|
|
* Both calls complete because the sets are equal (|| short-circuits only on false).
|
|
* Grand total: B*(B+1).
|
|
*
|
|
* Growth when B doubles: defective ≈4x (quadratic), fixed ≈2x (linear).
|
|
*/
|
|
public class BoundSetAlgorithm {
|
|
|
|
public static class Result {
|
|
public final boolean equivalent;
|
|
public final long comparisons;
|
|
Result(boolean equivalent, long comparisons) {
|
|
this.equivalent = equivalent;
|
|
this.comparisons = comparisons;
|
|
}
|
|
}
|
|
|
|
// ─── DEFECTIVE: List.containsAll() — O(B²) ───────────────────────────────
|
|
// Mirrors InferenceContext.isEquiv():506 — two mutual containsAll() checks.
|
|
|
|
public static Result isEquivDefective(List<Integer> b1, List<Integer> b2) {
|
|
long[] comparisons = {0};
|
|
if (!listContainsAll(b1, b2, comparisons)) return new Result(false, comparisons[0]);
|
|
if (!listContainsAll(b2, b1, comparisons)) return new Result(false, comparisons[0]);
|
|
return new Result(true, comparisons[0]);
|
|
}
|
|
|
|
private static boolean listContainsAll(List<Integer> haystack,
|
|
List<Integer> needles,
|
|
long[] comparisons) {
|
|
for (Integer needle : needles) {
|
|
boolean found = false;
|
|
for (Integer h : haystack) {
|
|
comparisons[0]++;
|
|
if (h.equals(needle)) { found = true; break; }
|
|
}
|
|
if (!found) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ─── FIXED: Set.equals() — O(B) ─────────────────────────────────────────
|
|
// Convert both lists to LinkedHashSet; use Set.equals() for comparison.
|
|
// Set.equals() iterates one set and calls contains() on the other: O(B) total.
|
|
|
|
public static Result isEquivFixed(List<Integer> b1, List<Integer> b2) {
|
|
Set<Integer> set1 = new LinkedHashSet<>(b1);
|
|
Set<Integer> set2 = new LinkedHashSet<>(b2);
|
|
long comparisons = 0;
|
|
if (set1.size() != set2.size()) return new Result(false, comparisons);
|
|
for (Integer x : set1) {
|
|
comparisons++; // one O(1) HashSet.contains()
|
|
if (!set2.contains(x)) return new Result(false, comparisons);
|
|
}
|
|
return new Result(true, comparisons);
|
|
}
|
|
|
|
// ─── Factories ───────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Forward list: [0, 1, 2, ..., B-1].
|
|
* Use as b1 — b2 reversed produces worst-case containsAll scan order.
|
|
*/
|
|
public static List<Integer> buildForwardList(int b) {
|
|
List<Integer> list = new ArrayList<>();
|
|
for (int i = 0; i < b; i++) list.add(i);
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
* Reversed list: [B-1, B-2, ..., 0].
|
|
* Use as b2 — each element found at the far end of the forward b1 list.
|
|
* This maximises the scan depth for each containsAll() lookup.
|
|
*/
|
|
public static List<Integer> buildReversedList(int b) {
|
|
List<Integer> list = new ArrayList<>();
|
|
for (int i = b - 1; i >= 0; i--) list.add(i);
|
|
return list;
|
|
}
|
|
}
|