package unit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * pulumi-0001: package_info.go Required slice O(P×R) membership test * * Slow: slices.Contains(Required, name) inside for _, name := range SortedKeys(Properties) — O(P×R) * Fast: pre-build requiredSet map[string]bool, then requiredSet[name] — O(P+R) * * Verifies: slow_ops >= P*(P-1)/2, fast_ops == P+R, ratio >= 10x at P=500, R=200 */ public class PulumiPackageInfoAlgorithm { static long slowOps = 0; static long fastOps = 0; /** Simulate slices.Contains — counts ops against slowOps */ static boolean slicesContains(List list, String target) { for (String s : list) { slowOps++; if (s.equals(target)) return true; } return false; } /** * Slow version: mirrors original package_info.go * for _, name := range maputil.SortedKeys(properties) { * if slices.Contains(required, name) { ... } * } */ static int slowDisplayProperties(Map properties, List required) { slowOps = 0; int requiredCount = 0; // SortedKeys produces sorted iteration for (String name : new TreeMap<>(properties).keySet()) { if (slicesContains(required, name)) { requiredCount++; } } return requiredCount; } /** * Fast version: pre-build a set for O(1) lookup * requiredSet := make(map[string]bool, len(required)) * for _, r := range required { requiredSet[r] = true } * for _, name := range sortedKeys { if requiredSet[name] { ... } } */ static int fastDisplayProperties(Map properties, List required) { fastOps = 0; Map requiredSet = new HashMap<>(required.size() * 2); for (String r : required) { fastOps++; requiredSet.put(r, true); } int requiredCount = 0; for (String name : new TreeMap<>(properties).keySet()) { fastOps++; if (requiredSet.containsKey(name)) { requiredCount++; } } return requiredCount; } /** Build a schema with P properties and R required fields */ static Object[] buildSchema(int P, int R) { Map properties = new TreeMap<>(); List required = new ArrayList<>(); for (int i = 0; i < P; i++) { String name = "prop_" + String.format("%04d", i); properties.put(name, "string"); if (i < R) { required.add(name); } } return new Object[]{properties, required}; } @SuppressWarnings("unchecked") public static void main(String[] args) { int passed = 0; int total = 0; // Test 1: correctness — both return same required count { total++; Object[] schema = buildSchema(20, 8); Map props = (Map) schema[0]; List required = (List) schema[1]; int slowResult = slowDisplayProperties(props, required); int fastResult = fastDisplayProperties(props, required); boolean ok = (slowResult == 8 && fastResult == 8); System.out.println((ok ? "PASS" : "FAIL") + " [correctness P=20 R=8]: slow=" + slowResult + " fast=" + fastResult); if (ok) passed++; } // Test 2: no required fields { total++; Object[] schema = buildSchema(10, 0); Map props = (Map) schema[0]; List required = (List) schema[1]; int slowResult = slowDisplayProperties(props, required); int fastResult = fastDisplayProperties(props, required); boolean ok = (slowResult == 0 && fastResult == 0); System.out.println((ok ? "PASS" : "FAIL") + " [no required P=10 R=0]: slow=" + slowResult + " fast=" + fastResult); if (ok) passed++; } // Test 3: all required { total++; Object[] schema = buildSchema(15, 15); Map props = (Map) schema[0]; List required = (List) schema[1]; int slowResult = slowDisplayProperties(props, required); int fastResult = fastDisplayProperties(props, required); boolean ok = (slowResult == 15 && fastResult == 15); System.out.println((ok ? "PASS" : "FAIL") + " [all required P=15 R=15]: slow=" + slowResult + " fast=" + fastResult); if (ok) passed++; } // Test 4: slow op count is O(P×R) { total++; int P = 500, R = 200; Object[] schema = buildSchema(P, R); slowDisplayProperties((Map) schema[0], (List) schema[1]); // For required properties: scan stops at position (roughly avg R/2 per hit + full scan for misses) // At minimum: R properties each stop at avg R/2 + (P-R) properties each scan full R = R²/2 + (P-R)*R long minExpected = (long) (P - R) * R; // just the non-required properties scanning full required list boolean ok = slowOps >= minExpected; System.out.println((ok ? "PASS" : "FAIL") + " [slow O(P×R) P=" + P + " R=" + R + "]: ops=" + slowOps + " >= " + minExpected); if (ok) passed++; } // Test 5: fast op count is O(P+R) { total++; int P = 500, R = 200; Object[] schema = buildSchema(P, R); fastDisplayProperties((Map) schema[0], (List) schema[1]); // fastOps = R (set build) + P (property scan) = P+R long expected = (long) P + R; boolean ok = fastOps == expected; System.out.println((ok ? "PASS" : "FAIL") + " [fast O(P+R) P=" + P + " R=" + R + "]: ops=" + fastOps + " == " + expected); if (ok) passed++; } // Test 6: ratio >= 10x at P=500, R=200 { total++; int P = 500, R = 200; Object[] schema = buildSchema(P, R); Map props = (Map) schema[0]; List required = (List) schema[1]; slowDisplayProperties(props, required); long slowCount = slowOps; fastDisplayProperties(props, required); long fastCount = fastOps; double ratio = (double) slowCount / fastCount; boolean ok = ratio >= 10.0; System.out.printf((ok ? "PASS" : "FAIL") + " [ratio P=%d R=%d]: slowOps=%d fastOps=%d ratio=%.1fx%n", P, R, slowCount, fastCount, ratio); if (ok) passed++; } System.out.println(passed + "/" + total + " PASS"); if (passed != total) System.exit(1); } }