wave11: 488/227 — ROS2/OpenCV/Open3D/metaflow/kubeflow/optuna/openssl/mbedtls/wolfssl + Kafka Streams/Pulsar

This commit is contained in:
russell@unturf.com 2026-03-27 17:31:52 -04:00
parent 6276aea2e5
commit 19333b378e
36 changed files with 4634 additions and 5 deletions

View file

@ -0,0 +1,262 @@
package unit;
import java.util.*;
/**
* metaflow-0001 O(N²) graph traversal in FlowGraph._traverse_graph()
*
* Simulates the defective pattern from:
* metaflow/graph.py lines 300-340
*
* Defect 1: sorted_nodes.remove(node.name) is O(N) inside a DFS that visits N nodes O(N²)
* Defect 2: seen is a List, so `n not in seen` is O(depth) per edge O(N²) summed over all edges
*
* Fix 1: Use a LinkedHashMap (insertion-ordered map) for sorted_nodes O(1) remove/put
* Fix 2: Use a HashSet for seen O(1) membership test
*
* The op-count measures "list scans": how many elements were examined across all
* remove() and `contains()` calls. In the defective version this is O(N²);
* in the fixed version it is O(N + E).
*/
public class MetaflowGraphAlgorithm {
static void check(String desc, boolean cond) {
System.out.println((cond ? "PASS" : "FAIL") + ": " + desc);
if (!cond) throw new AssertionError("FAIL: " + desc);
}
// Simulates a DAGNode with successors
static class Node {
final String name;
final List<String> outFuncs = new ArrayList<>();
Node(String name) { this.name = name; }
void addEdge(String target) { outFuncs.add(target); }
}
// Result from traversal
static class Result {
final List<String> sortedNodes;
final long listScans;
Result(List<String> sortedNodes, long listScans) {
this.sortedNodes = sortedNodes;
this.listScans = listScans;
}
}
// -----------------------------------------------------------------------
// DEFECTIVE: sorted_nodes is an ArrayList, seen is a List
// -----------------------------------------------------------------------
static long defectiveScans;
static void traverseDefective(
String name,
Map<String, Node> nodes,
List<String> sortedNodes,
List<String> seen) {
// O(N) scan: remove from list
int sizeBefore = sortedNodes.size();
sortedNodes.remove(name);
defectiveScans += sizeBefore; // counted even if not found
sortedNodes.add(name);
for (String n : nodes.get(name).outFuncs) {
// O(depth) scan: check membership
defectiveScans += seen.size();
if (!seen.contains(n)) {
if (nodes.containsKey(n)) {
List<String> newSeen = new ArrayList<>(seen);
newSeen.add(n);
traverseDefective(n, nodes, sortedNodes, newSeen);
}
}
}
}
static Result runDefective(Map<String, Node> nodes, String start) {
defectiveScans = 0;
List<String> sortedNodes = new ArrayList<>();
List<String> seen = new ArrayList<>();
seen.add(start);
traverseDefective(start, nodes, sortedNodes, seen);
return new Result(sortedNodes, defectiveScans);
}
// -----------------------------------------------------------------------
// FIXED: sorted_nodes is a LinkedHashMap, seen is a HashSet
// -----------------------------------------------------------------------
static long fixedScans;
static void traverseFixed(
String name,
Map<String, Node> nodes,
LinkedHashMap<String, Boolean> sortedNodes,
Set<String> seen) {
// O(1) remove + put
sortedNodes.remove(name); // no scan needed
sortedNodes.put(name, true);
fixedScans += 1; // count the O(1) hash op
for (String n : nodes.get(name).outFuncs) {
// O(1) hash lookup
fixedScans += 1;
if (!seen.contains(n)) {
if (nodes.containsKey(n)) {
seen.add(n);
traverseFixed(n, nodes, sortedNodes, seen);
}
}
}
}
static Result runFixed(Map<String, Node> nodes, String start) {
fixedScans = 0;
LinkedHashMap<String, Boolean> sortedNodes = new LinkedHashMap<>();
Set<String> seen = new HashSet<>();
seen.add(start);
traverseFixed(start, nodes, sortedNodes, seen);
return new Result(new ArrayList<>(sortedNodes.keySet()), fixedScans);
}
// -----------------------------------------------------------------------
// Build a linear chain: start s1 s2 ... sN end
// -----------------------------------------------------------------------
static Map<String, Node> linearChain(int n) {
Map<String, Node> nodes = new LinkedHashMap<>();
Node start = new Node("start");
nodes.put("start", start);
String prev = "start";
for (int i = 1; i <= n; i++) {
String name = "step" + i;
Node node = new Node(name);
nodes.put(name, node);
nodes.get(prev).addEdge(name);
prev = name;
}
Node end = new Node("end");
nodes.put("end", end);
nodes.get(prev).addEdge("end");
return nodes;
}
// -----------------------------------------------------------------------
// Build a diamond DAG (wide split): start N parallel join end
// -----------------------------------------------------------------------
static Map<String, Node> diamondDAG(int n) {
Map<String, Node> nodes = new LinkedHashMap<>();
Node start = new Node("start");
nodes.put("start", start);
Node join = new Node("join");
nodes.put("join", join);
for (int i = 0; i < n; i++) {
String name = "branch" + i;
Node b = new Node(name);
nodes.put(name, b);
start.addEdge(name);
b.addEdge("join");
}
Node end = new Node("end");
nodes.put("end", end);
join.addEdge("end");
return nodes;
}
public static void main(String[] args) {
System.out.println("=== metaflow-0001: O(N²) graph traverse in FlowGraph._traverse_graph ===");
// ------ Test 1: correctness on small linear chain ------
{
Map<String, Node> nodes = linearChain(4);
Result def = runDefective(nodes, "start");
Result fix = runFixed(nodes, "start");
check("linear-4: defective produces correct topo order",
def.sortedNodes.equals(Arrays.asList("start","step1","step2","step3","step4","end")));
check("linear-4: fixed produces correct topo order",
fix.sortedNodes.equals(Arrays.asList("start","step1","step2","step3","step4","end")));
check("linear-4: fixed uses fewer scans",
fix.listScans <= def.listScans);
}
// ------ Test 2: O(N²) vs O(N) scaling on linear chain ------
{
int N = 200;
Map<String, Node> nodes = linearChain(N);
Result def200 = runDefective(nodes, "start");
Result fix200 = runFixed(nodes, "start");
// Defective: remove scans grow as 0+1+2+...+N N²/2; seen grows too
// Fixed: each op is O(1)
long ratio = def200.listScans / Math.max(fix200.listScans, 1);
System.out.printf(" N=%d: defective scans=%d, fixed scans=%d, ratio=%dx%n",
N, def200.listScans, fix200.listScans, ratio);
check("linear-200: defective scan count > 1000 (quadratic evidence)",
def200.listScans > 1_000);
check("linear-200: fixed scan count <= 2*(N+2) (linear)",
fix200.listScans <= 2L * (N + 2));
check("linear-200: ratio >= 10x",
ratio >= 10);
// Verify both produce same sorted order
check("linear-200: same sorted order",
def200.sortedNodes.equals(fix200.sortedNodes));
}
// ------ Test 3: diamond DAG correctness ------
{
int N = 50;
Map<String, Node> nodes = diamondDAG(N);
Result def = runDefective(nodes, "start");
Result fix = runFixed(nodes, "start");
// start must be first in both versions, all nodes visited, same count
check("diamond-50: start is first (defective)", def.sortedNodes.get(0).equals("start"));
check("diamond-50: start is first (fixed)", fix.sortedNodes.get(0).equals("start"));
// Both must contain all N+3 nodes: start, N branches, join, end
check("diamond-50: defective visits all nodes", def.sortedNodes.size() == N + 3);
check("diamond-50: fixed visits all nodes", fix.sortedNodes.size() == N + 3);
// join must appear before end in both (topological constraint)
int defJoinIdx = def.sortedNodes.indexOf("join");
int defEndIdx = def.sortedNodes.indexOf("end");
int fixJoinIdx = fix.sortedNodes.indexOf("join");
int fixEndIdx = fix.sortedNodes.indexOf("end");
check("diamond-50: join before end (defective)", defJoinIdx < defEndIdx);
check("diamond-50: join before end (fixed)", fixJoinIdx < fixEndIdx);
// all branches are present in fixed output
check("diamond-50: fixed contains branch0", fix.sortedNodes.contains("branch0"));
check("diamond-50: fixed contains branch" + (N-1), fix.sortedNodes.contains("branch" + (N-1)));
}
// ------ Test 4: large chain quadratic cost is clear ------
{
int N = 400;
Map<String, Node> small = linearChain(N / 4);
Map<String, Node> large = linearChain(N);
Result defSmall = runDefective(small, "start");
Result defLarge = runDefective(large, "start");
// Quadratic: scans should grow roughly 16× (4× nodes 16× scans)
double growthRatio = (double) defLarge.listScans / Math.max(defSmall.listScans, 1);
System.out.printf(" Defective: N=%d scans=%d, N=%d scans=%d, growth=%.1fx%n",
N/4, defSmall.listScans, N, defLarge.listScans, growthRatio);
check("quadratic growth: defLarge.scans > 4x defSmall.scans (O(N²) evidence)",
growthRatio > 4.0);
Result fixSmall = runFixed(small, "start");
Result fixLarge = runFixed(large, "start");
double fixGrowthRatio = (double) fixLarge.listScans / Math.max(fixSmall.listScans, 1);
System.out.printf(" Fixed: N=%d scans=%d, N=%d scans=%d, growth=%.1fx%n",
N/4, fixSmall.listScans, N, fixLarge.listScans, fixGrowthRatio);
check("linear growth: fixLarge.scans < 5x fixSmall.scans (O(N) evidence)",
fixGrowthRatio < 5.0);
}
System.out.println("All tests PASS.");
}
}