wave8c: 452/202 — envoy/cilium, graph-dbs, elixir/nim, k8s/maven + PDF
This commit is contained in:
parent
c4330be5b0
commit
3c0b3edc79
49 changed files with 3820 additions and 8 deletions
160
defects/nim/unit/NimCyclicTreeAlgorithm.java
Normal file
160
defects/nim/unit/NimCyclicTreeAlgorithm.java
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* NimCyclicTreeAlgorithm — CWE-407 test for nim-0002
|
||||
*
|
||||
* Models trees.cyclicTreeAux(n, visited):
|
||||
* slow: for v in visited: if v == n — O(N) scan per node, O(N²) for path tree
|
||||
* fast: HashSet[pointer] visited — O(1) per node, O(N) total
|
||||
*
|
||||
* Test: on a path graph (depth=N), slow does O(N²) scans; fast does O(N) ops.
|
||||
*/
|
||||
public class NimCyclicTreeAlgorithm {
|
||||
|
||||
// Simple tree node (PNode proxy)
|
||||
static class PNode {
|
||||
final int id;
|
||||
final List<PNode> sons;
|
||||
PNode(int id) { this.id = id; this.sons = new ArrayList<>(); }
|
||||
}
|
||||
|
||||
// --- SLOW: O(N²) ---
|
||||
// for v in visited: if v == n: return true
|
||||
// visited is a path-stack (ArrayList acting as seq with add/remove)
|
||||
static class SlowCyclicCheck {
|
||||
long scanOps = 0;
|
||||
|
||||
boolean cyclicTreeAux(PNode n, List<PNode> visited) {
|
||||
if (n == null) return false;
|
||||
// Linear scan of visited (the path stack)
|
||||
for (PNode v : visited) {
|
||||
scanOps++;
|
||||
if (v == n) return true;
|
||||
}
|
||||
visited.add(n);
|
||||
for (PNode son : n.sons) {
|
||||
if (cyclicTreeAux(son, visited)) return true;
|
||||
}
|
||||
visited.remove(visited.size() - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean cyclicTree(PNode n) {
|
||||
List<PNode> visited = new ArrayList<>();
|
||||
return cyclicTreeAux(n, visited);
|
||||
}
|
||||
}
|
||||
|
||||
// --- FAST: O(N) ---
|
||||
// visited is a HashSet[pointer] (IdentityHashMap backed set)
|
||||
static class FastCyclicCheck {
|
||||
long hashOps = 0;
|
||||
|
||||
// Using IdentityHashMap to simulate pointer-based HashSet
|
||||
boolean cyclicTreeAux(PNode n, Set<PNode> visited) {
|
||||
if (n == null) return false;
|
||||
hashOps++;
|
||||
if (visited.contains(n)) return true; // O(1) identity hash
|
||||
visited.add(n);
|
||||
for (PNode son : n.sons) {
|
||||
if (cyclicTreeAux(son, visited)) return true;
|
||||
}
|
||||
visited.remove(n);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean cyclicTree(PNode n) {
|
||||
// IdentityHashMap simulates pointer-equality HashSet (Nim's HashSet[pointer])
|
||||
Set<PNode> visited = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
return cyclicTreeAux(n, visited);
|
||||
}
|
||||
}
|
||||
|
||||
// Build an acyclic path graph: 0 -> 1 -> 2 -> ... -> n-1
|
||||
// This is worst case for the slow algorithm: depth = n, visited grows to n
|
||||
static PNode buildPathGraph(int n) {
|
||||
PNode[] nodes = new PNode[n];
|
||||
for (int i = 0; i < n; i++) nodes[i] = new PNode(i);
|
||||
for (int i = 0; i < n - 1; i++) nodes[i].sons.add(nodes[i + 1]);
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
// Build a balanced binary tree of depth d (no cycles)
|
||||
static PNode buildBinaryTree(int depth) {
|
||||
if (depth == 0) return new PNode(0);
|
||||
PNode root = new PNode(depth);
|
||||
root.sons.add(buildBinaryTree(depth - 1));
|
||||
root.sons.add(buildBinaryTree(depth - 1));
|
||||
return root;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("NimCyclicTreeAlgorithm — nim-0002");
|
||||
System.out.println(" Pattern: for v in visited: if v == n — O(N²) vs HashSet — O(N)");
|
||||
System.out.println();
|
||||
|
||||
int passed = 0;
|
||||
int total = 0;
|
||||
|
||||
// Test 1: Path graphs (worst case for O(N²))
|
||||
int[] pathSizes = {100, 300, 500, 800};
|
||||
for (int n : pathSizes) {
|
||||
PNode root = buildPathGraph(n);
|
||||
|
||||
SlowCyclicCheck slow = new SlowCyclicCheck();
|
||||
FastCyclicCheck fast = new FastCyclicCheck();
|
||||
|
||||
boolean slowResult = slow.cyclicTree(root);
|
||||
boolean fastResult = fast.cyclicTree(root);
|
||||
|
||||
long slowOps = slow.scanOps;
|
||||
long fastOps = fast.hashOps;
|
||||
|
||||
// No cycles — both should return false
|
||||
boolean correctResult = !slowResult && !fastResult;
|
||||
|
||||
// Slow: at depth d, visited has d nodes. Sum for path of N nodes: 0+1+2+...+(N-1) = N(N-1)/2
|
||||
boolean slowIsQuadratic = slowOps >= (long) n * (n - 1) / 4; // conservative
|
||||
boolean fastIsLinear = fastOps <= n + 1; // at most N+1 hash checks
|
||||
|
||||
total += 3;
|
||||
if (correctResult) { System.out.println("PASS path N=" + n + ": no cycle detected (correct)"); passed++; }
|
||||
else { System.out.println("FAIL path N=" + n + ": wrong cycle detection slow=" + slowResult + " fast=" + fastResult); }
|
||||
|
||||
if (slowIsQuadratic) { System.out.println("PASS path N=" + n + ": slow O(N²) scans=" + slowOps + " >= N(N-1)/4=" + (n * (n - 1) / 4)); passed++; }
|
||||
else { System.out.println("FAIL path N=" + n + ": slow not quadratic, scans=" + slowOps); }
|
||||
|
||||
if (fastIsLinear) { System.out.println("PASS path N=" + n + ": fast O(N) ops=" + fastOps + " <= N+1=" + (n + 1)); passed++; }
|
||||
else { System.out.println("FAIL path N=" + n + ": fast not linear, ops=" + fastOps); }
|
||||
}
|
||||
|
||||
// Test 2: Cycle detection correctness — introduce a back edge
|
||||
{
|
||||
PNode[] nodes = new PNode[5];
|
||||
for (int i = 0; i < 5; i++) nodes[i] = new PNode(i);
|
||||
nodes[0].sons.add(nodes[1]);
|
||||
nodes[1].sons.add(nodes[2]);
|
||||
nodes[2].sons.add(nodes[0]); // cycle: 2 -> 0
|
||||
|
||||
SlowCyclicCheck slow = new SlowCyclicCheck();
|
||||
FastCyclicCheck fast = new FastCyclicCheck();
|
||||
|
||||
boolean slowDetects = slow.cyclicTree(nodes[0]);
|
||||
boolean fastDetects = fast.cyclicTree(nodes[0]);
|
||||
|
||||
total += 2;
|
||||
if (slowDetects) { System.out.println("PASS cycle: slow correctly detects cycle"); passed++; }
|
||||
else { System.out.println("FAIL cycle: slow missed cycle"); }
|
||||
if (fastDetects) { System.out.println("PASS cycle: fast correctly detects cycle"); passed++; }
|
||||
else { System.out.println("FAIL cycle: fast missed cycle"); }
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println(passed + "/" + total + " PASS");
|
||||
if (passed != total) {
|
||||
throw new AssertionError(passed + "/" + total + " tests passed");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue