155 lines
5.3 KiB
Java
155 lines
5.3 KiB
Java
package unit;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* ansible-0001: Role.get_vars() seen-list O(D²) deduplication
|
|
*
|
|
* Slow: uses List for seen-set — dep not in seen is O(D) per iteration → O(D²) total
|
|
* Fast: uses HashSet for seen-set — dep not in seen is O(1) per iteration → O(D) total
|
|
*
|
|
* Verifies: slow_ops >= D*(D-1)/2, fast_ops == D, ratio >= 10x at D=200
|
|
*/
|
|
public class AnsibleRoleGetVarsAlgorithm {
|
|
|
|
static long slowOps = 0;
|
|
static long fastOps = 0;
|
|
|
|
/** Simulated Role dependency — identity-based equality (no custom equals/hashCode) */
|
|
static class MockDep {
|
|
final int id;
|
|
MockDep(int id) { this.id = id; }
|
|
}
|
|
|
|
/**
|
|
* Slow version: seen is an ArrayList — contains() is O(D)
|
|
* Mirrors: seen = []; if dep not in seen: seen.append(dep)
|
|
*/
|
|
static int slowGetVars(List<MockDep> allDependencies) {
|
|
slowOps = 0;
|
|
List<MockDep> seen = new ArrayList<>();
|
|
int combinedCount = 0;
|
|
for (MockDep dep : allDependencies) {
|
|
// Each call to contains() scans the entire seen list — O(seen.size())
|
|
for (MockDep s : seen) {
|
|
slowOps++;
|
|
if (s == dep) break; // found
|
|
}
|
|
// Equivalent of: if dep not in seen
|
|
boolean inSeen = false;
|
|
for (MockDep s : seen) {
|
|
if (s == dep) { inSeen = true; break; }
|
|
}
|
|
if (!inSeen) {
|
|
// combine_vars equivalent
|
|
combinedCount++;
|
|
seen.add(dep);
|
|
}
|
|
}
|
|
return combinedCount;
|
|
}
|
|
|
|
/**
|
|
* Fast version: seen is a HashSet — contains() is O(1)
|
|
* Mirrors: seen = set(); if dep not in seen: seen.add(dep)
|
|
*/
|
|
static int fastGetVars(List<MockDep> allDependencies) {
|
|
fastOps = 0;
|
|
Set<MockDep> seen = new HashSet<>();
|
|
int combinedCount = 0;
|
|
for (MockDep dep : allDependencies) {
|
|
fastOps++;
|
|
if (!seen.contains(dep)) {
|
|
combinedCount++;
|
|
seen.add(dep);
|
|
}
|
|
}
|
|
return combinedCount;
|
|
}
|
|
|
|
/**
|
|
* Build a dependency list with D unique deps, no duplicates (worst case for seen growth).
|
|
*/
|
|
static List<MockDep> buildDeps(int D) {
|
|
List<MockDep> deps = new ArrayList<>();
|
|
for (int i = 0; i < D; i++) {
|
|
deps.add(new MockDep(i));
|
|
}
|
|
return deps;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
int passed = 0;
|
|
int total = 0;
|
|
|
|
// Test 1: basic correctness — both produce same combined count
|
|
{
|
|
total++;
|
|
int D = 10;
|
|
List<MockDep> deps = buildDeps(D);
|
|
int slowResult = slowGetVars(deps);
|
|
int fastResult = fastGetVars(deps);
|
|
boolean ok = (slowResult == D && fastResult == D);
|
|
System.out.println((ok ? "PASS" : "FAIL") + " [correctness D=" + D + "]: slow=" + slowResult + " fast=" + fastResult);
|
|
if (ok) passed++;
|
|
}
|
|
|
|
// Test 2: with duplicates — both should deduplicate identically
|
|
{
|
|
total++;
|
|
int D = 5;
|
|
List<MockDep> unique = buildDeps(D);
|
|
List<MockDep> depsWithDups = new ArrayList<>();
|
|
for (MockDep dep : unique) { depsWithDups.add(dep); depsWithDups.add(dep); } // each dep appears twice
|
|
int slowResult = slowGetVars(depsWithDups);
|
|
int fastResult = fastGetVars(depsWithDups);
|
|
boolean ok = (slowResult == D && fastResult == D);
|
|
System.out.println((ok ? "PASS" : "FAIL") + " [dedup D=" + D + " with dupes]: slow=" + slowResult + " fast=" + fastResult);
|
|
if (ok) passed++;
|
|
}
|
|
|
|
// Test 3: slow op count is O(D²) — at least D*(D-1)/2 comparisons
|
|
{
|
|
total++;
|
|
int D = 200;
|
|
List<MockDep> deps = buildDeps(D);
|
|
slowGetVars(deps);
|
|
long minExpectedSlowOps = (long) D * (D - 1) / 2;
|
|
boolean ok = slowOps >= minExpectedSlowOps;
|
|
System.out.println((ok ? "PASS" : "FAIL") + " [slow O(D²) D=" + D + "]: ops=" + slowOps + " >= " + minExpectedSlowOps);
|
|
if (ok) passed++;
|
|
}
|
|
|
|
// Test 4: fast op count is exactly O(D) — one check per dep
|
|
{
|
|
total++;
|
|
int D = 200;
|
|
List<MockDep> deps = buildDeps(D);
|
|
fastGetVars(deps);
|
|
boolean ok = (fastOps == D);
|
|
System.out.println((ok ? "PASS" : "FAIL") + " [fast O(D) D=" + D + "]: ops=" + fastOps + " == " + D);
|
|
if (ok) passed++;
|
|
}
|
|
|
|
// Test 5: ratio >= 10x at D=200
|
|
{
|
|
total++;
|
|
int D = 200;
|
|
List<MockDep> deps = buildDeps(D);
|
|
slowGetVars(deps);
|
|
long slowCount = slowOps;
|
|
fastGetVars(deps);
|
|
long fastCount = fastOps;
|
|
double ratio = (double) slowCount / fastCount;
|
|
boolean ok = ratio >= 10.0;
|
|
System.out.printf((ok ? "PASS" : "FAIL") + " [ratio D=%d]: slowOps=%d fastOps=%d ratio=%.1fx%n", D, slowCount, fastCount, ratio);
|
|
if (ok) passed++;
|
|
}
|
|
|
|
System.out.println(passed + "/" + total + " PASS");
|
|
if (passed != total) System.exit(1);
|
|
}
|
|
}
|