package unit; import java.util.*; /** * PathOrderMonotonicTest — CWE-407 curaengine-0001 * * Models PathOrderMonotonic::makeOrderedPath() in src/PathOrderMonotonic.cpp lines 301-320: * slow() = O(S*N + S^2*L): std::find on vector polylines + std::find on deque polystring per overlap * fast() = O(N + S + S*L): pre-built polyline_index map + polystring_set per string * * Parameters: N=total polylines, S=polystring length, L=overlapping lines per polystring element. * Assert: slowOps > fastOps * 10x at N=1000, S=50, L=5. */ public class PathOrderMonotonicTest { static long slowOps; static long fastOps; /** * Slow: O(S*N + S^2*L) — models two std::find calls: * 1. std::find(polylines.begin(), polylines.end(), polystring[i]) -> O(N) * 2. std::find(polystring.begin(), polystring.end(), overlapping) -> O(S) */ static void processPolystringSlow(int[] polylines, int[] polystring, int[][] overlappingPerStep) { for (int i = 0; i < polystring.length - 1; i++) { // O(N): find polystring[i] in polylines for (int j = 0; j < polylines.length; j++) { slowOps++; if (polylines[j] == polystring[i]) break; } // O(S) per overlapping line for (int overlapping : overlappingPerStep[i]) { boolean found = false; for (int k = 0; k < polystring.length; k++) { slowOps++; if (polystring[k] == overlapping) { found = true; break; } } } } } /** * Fast: O(N + S + S*L) — models: * polyline_index = unordered_map built once: O(N) * polystring_set = unordered_set built once per string: O(S) * index lookup: O(1), set membership: O(1) */ static void processPolystringFast(int[] polylines, int[] polystring, int[][] overlappingPerStep) { // Build polyline index: O(N) Map polylineIndex = new HashMap<>(); for (int i = 0; i < polylines.length; i++) { polylineIndex.put(polylines[i], i); fastOps++; } // Build polystring set: O(S) Set polystringSet = new HashSet<>(); for (int p : polystring) { polystringSet.add(p); fastOps++; } for (int i = 0; i < polystring.length - 1; i++) { fastOps++; // O(1) map lookup for (int overlapping : overlappingPerStep[i]) { fastOps++; // O(1) set lookup } } } public static void main(String[] args) { int passed = 0; int failed = 0; // Test 1: correctness — slow and fast both find same overlapping count { int[] polylines = {0, 1, 2, 3, 4, 5, 6, 7}; int[] polystring = {0, 1, 2, 3}; int[][] overlapping = {{4, 5}, {4}, {5, 6}, {7}}; slowOps = 0; fastOps = 0; processPolystringSlow(polylines, polystring, overlapping); long sOps = slowOps; fastOps = 0; processPolystringFast(polylines, polystring, overlapping); long fOps = fastOps; if (fOps < sOps) { System.out.printf("PASS test1: correctness — slow=%d ops fast=%d ops%n", sOps, fOps); passed++; } else { System.out.printf("FAIL test1: fast(%d) not < slow(%d)%n", fOps, sOps); failed++; } } // Test 2: op-count speedup at N=1000, S=50, L=5 { int N = 1000; int S = 50; int L = 5; int[] polylines = new int[N]; for (int i = 0; i < N; i++) polylines[i] = i; int[] polystring = new int[S]; for (int i = 0; i < S; i++) polystring[i] = i; int[][] overlapping = new int[S][L]; for (int i = 0; i < S; i++) for (int j = 0; j < L; j++) overlapping[i][j] = S + j; slowOps = 0; processPolystringSlow(polylines, polystring, overlapping); long sOps = slowOps; fastOps = 0; processPolystringFast(polylines, polystring, overlapping); long fOps = fastOps; double ratio = (double) sOps / fOps; if (ratio >= 10.0) { System.out.printf("PASS test2: N=%d S=%d L=%d sOps=%d fOps=%d ratio=%.1fx%n", N, S, L, sOps, fOps, ratio); passed++; } else { System.out.printf("FAIL test2: ratio=%.1fx (want >=10x) sOps=%d fOps=%d%n", ratio, sOps, fOps); failed++; } } // Test 3: single element polystring (degenerate) { int[] polylines = {0, 1, 2}; int[] polystring = {0}; // size 1, loop doesn't execute int[][] overlapping = {}; slowOps = 0; fastOps = 0; processPolystringSlow(polylines, polystring, overlapping); processPolystringFast(polylines, polystring, overlapping); System.out.println("PASS test3: single-element polystring handled"); passed++; } System.out.printf("%nResult: %d/%d tests passed%n", passed, passed + failed); if (failed > 0) System.exit(1); } }