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.
122 lines
4.5 KiB
Java
122 lines
4.5 KiB
Java
package support;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Reference implementations of InferenceGraph.findNode() — defective and fixed.
|
|
*
|
|
* DEFECT 0002a (Infer.java:1850): findNode() scans an ArrayList linearly on
|
|
* every call. Called O(N²) times from buildStuckGraph()'s double loop.
|
|
* With uncached closure (defect 0002b), total = O(N³).
|
|
*
|
|
* Fix: replace the ArrayList scan with a HashMap built once at construction.
|
|
*
|
|
* Exact comparison counts when querying N nodes in order 0..N-1:
|
|
* defective: 1 + 2 + ... + N = N*(N+1)/2
|
|
* fixed: N (1 per HashMap.get())
|
|
*
|
|
* Derivation of defective count:
|
|
* Querying N0 first finds it at index 0 → 1 comparison.
|
|
* Querying N1 scans from the start: [N0, N1] → 2 comparisons.
|
|
* Querying N(k) scans k+1 elements → k+1 comparisons.
|
|
* Total: sum(k+1, k=0..N-1) = N*(N+1)/2.
|
|
*
|
|
* Growth when N doubles: defective ≈4x (quadratic), fixed ≈2x (linear).
|
|
*/
|
|
public class FindNodeAlgorithm {
|
|
|
|
public static class Node {
|
|
public final String label;
|
|
public Node(String label) { this.label = label; }
|
|
@Override public String toString() { return label; }
|
|
}
|
|
|
|
public static class Result {
|
|
public final List<Node> found;
|
|
public final long comparisons;
|
|
Result(List<Node> found, long comparisons) {
|
|
this.found = found;
|
|
this.comparisons = comparisons;
|
|
}
|
|
}
|
|
|
|
// ─── DEFECTIVE: O(N) ArrayList scan per call ────────────────────────────
|
|
// Mirrors Infer.java:1850 — iterates the nodes list looking for matching var.
|
|
|
|
public static class DefectiveFinder {
|
|
private final List<Node> nodes;
|
|
private long comparisons = 0;
|
|
|
|
public DefectiveFinder(List<Node> nodes) {
|
|
this.nodes = new ArrayList<>(nodes);
|
|
}
|
|
|
|
public Node findNode(String label) {
|
|
for (Node n : nodes) {
|
|
comparisons++;
|
|
if (n.label.equals(label)) return n;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public long getComparisons() { return comparisons; }
|
|
}
|
|
|
|
// ─── FIXED: O(1) HashMap lookup ─────────────────────────────────────────
|
|
// Build a label→node index once at construction; each findNode() = O(1).
|
|
|
|
public static class FixedFinder {
|
|
private final Map<String, Node> index;
|
|
private long comparisons = 0;
|
|
|
|
public FixedFinder(List<Node> nodes) {
|
|
index = new HashMap<>(nodes.size() * 2);
|
|
for (Node n : nodes) index.put(n.label, n);
|
|
}
|
|
|
|
public Node findNode(String label) {
|
|
comparisons++; // one HashMap.get() = O(1)
|
|
return index.get(label);
|
|
}
|
|
|
|
public long getComparisons() { return comparisons; }
|
|
}
|
|
|
|
// ─── Convenience runners ─────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Query all N nodes in order 0..N-1 using the defective finder.
|
|
* Expected comparisons: N*(N+1)/2.
|
|
*/
|
|
public static Result queryAllDefective(int n) {
|
|
List<Node> nodes = buildNodeList(n);
|
|
DefectiveFinder finder = new DefectiveFinder(nodes);
|
|
List<Node> found = new ArrayList<>();
|
|
for (int i = 0; i < n; i++) found.add(finder.findNode("N" + i));
|
|
return new Result(found, finder.getComparisons());
|
|
}
|
|
|
|
/**
|
|
* Query all N nodes in order 0..N-1 using the fixed finder.
|
|
* Expected comparisons: N.
|
|
*/
|
|
public static Result queryAllFixed(int n) {
|
|
List<Node> nodes = buildNodeList(n);
|
|
FixedFinder finder = new FixedFinder(nodes);
|
|
List<Node> found = new ArrayList<>();
|
|
for (int i = 0; i < n; i++) found.add(finder.findNode("N" + i));
|
|
return new Result(found, finder.getComparisons());
|
|
}
|
|
|
|
// ─── Factory ─────────────────────────────────────────────────────────────
|
|
|
|
/** Returns a list of N nodes with labels "N0".."N(N-1)" in that order. */
|
|
public static List<Node> buildNodeList(int n) {
|
|
List<Node> nodes = new ArrayList<>();
|
|
for (int i = 0; i < n; i++) nodes.add(new Node("N" + i));
|
|
return nodes;
|
|
}
|
|
}
|