package unit; import java.util.*; /** * Models KiCad ZONE_FILLER::Fill() iterative refill dedup. * * SLOW: O(Z_r × Z × L × Z×L) — std::find on growing vector per (zone, layer) pair. * FAST: O(Z_r × Z × L) — HashSet dedup, O(1) insert/contains. * * CWE-407: pcbnew/zone_filler.cpp:998 (ZONE_FILLER::Fill iterative refill path) */ public class KicadZoneFillerAlgorithmTest { record ZoneLayer(int zoneId, int layerId) {} // ------------------------------------------------------------------------- // Slow — std::find O(N) scan on growing list // ------------------------------------------------------------------------- static class SlowZoneFiller { long cmpOps = 0; boolean find(List list, ZoneLayer item) { for (ZoneLayer zl : list) { cmpOps++; if (zl.equals(item)) return true; } return false; } List getZonesToRefill(int zRemoved, int zTotal, int layers) { List zonesToRefill = new ArrayList<>(); for (int r = 0; r < zRemoved; r++) { for (int z = 0; z < zTotal; z++) { for (int l = 0; l < layers; l++) { ZoneLayer item = new ZoneLayer(z, l); if (!find(zonesToRefill, item)) { zonesToRefill.add(item); } } } } return zonesToRefill; } long ops(int zRemoved, int zTotal, int layers) { cmpOps = 0; getZonesToRefill(zRemoved, zTotal, layers); return cmpOps; } } // ------------------------------------------------------------------------- // Fast — HashSet O(1) dedup // ------------------------------------------------------------------------- static class FastZoneFiller { long cmpOps = 0; List getZonesToRefill(int zRemoved, int zTotal, int layers) { Set seen = new HashSet<>(); List zonesToRefill = new ArrayList<>(); for (int r = 0; r < zRemoved; r++) { for (int z = 0; z < zTotal; z++) { for (int l = 0; l < layers; l++) { ZoneLayer item = new ZoneLayer(z, l); cmpOps++; if (seen.add(item)) { zonesToRefill.add(item); } } } } return zonesToRefill; } long ops(int zRemoved, int zTotal, int layers) { cmpOps = 0; getZonesToRefill(zRemoved, zTotal, layers); return cmpOps; } } public static void main(String[] args) { SlowZoneFiller slow = new SlowZoneFiller(); FastZoneFiller fast = new FastZoneFiller(); int passed = 0, total = 0; System.out.println("=== kicad-0002: zone_filler std::find O(Z²×L²) ==="); // (zRemoved, zTotal, layers) int[][] configs = { {5, 20, 2}, // small board {10, 50, 4}, // realistic (agent's estimate) {15, 100, 6}, // large board }; for (int[] cfg : configs) { int zr = cfg[0], z = cfg[1], l = cfg[2]; long s = slow.ops(zr, z, l); long f = fast.ops(zr, z, l); double ratio = (double) s / Math.max(f, 1); total++; boolean ok = s > f && ratio >= 5.0; System.out.printf("Zr=%2d Z=%3d L=%d slow=%9d fast=%6d ratio=%6.1fx %s%n", zr, z, l, s, f, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; } // Correctness: both produce same set of zones to refill SlowZoneFiller s2 = new SlowZoneFiller(); FastZoneFiller f2 = new FastZoneFiller(); List sr = s2.getZonesToRefill(10, 50, 4); List fr = f2.getZonesToRefill(10, 50, 4); Set ss = new HashSet<>(sr), fs = new HashSet<>(fr); total++; boolean correct = ss.equals(fs); System.out.printf("correctness (%d zones to refill): %s%n", sr.size(), correct ? "PASS" : "FAIL"); if (correct) passed++; System.out.printf("%n%d/%d PASS%n", passed, total); if (passed < total) System.exit(1); } }