Zigzag engine (6802 lines, 184 tests): - Construction 17 normalisation: working through dimension 3+ - Import from homotopy-rs JSON: working (scalar, two_scalars, half_braid) - Piece extraction via Embedding/restrict_diagram: working - Type checking pipeline: working (Eckmann-Hilton half_braid passes) - Essential identity detection: validated with full 2-diagram test Bugs found and fixed: - assemble_factorisations losing cospan legs during reassembly - RewriteN::slice() using source offsets instead of target indices - singular_preimage() not handling passthrough heights - restrict_rewrite() not accounting for accumulated cone offsets - Embedding::preimage() using regular_preimage for Singular case Added vis-engine-spec.md: visualization engine specification - 6-layer architecture from math primitives to scene graph - SVG renderer for 2D, WebGL2 for 3D, custom hit testing - Spring constraint integration point for semiotic rendering - No external dependencies - game engine approach Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
115 lines
4.6 KiB
Rust
115 lines
4.6 KiB
Rust
//! Trace scaffold nodes for visible wires through all time heights
|
|
//!
|
|
//! Run with: cargo run --example trace_scaffold
|
|
|
|
use std::fs;
|
|
use zigzag_engine::diagram::Diagram;
|
|
use zigzag_engine::import::load_homotopy_diagram_n;
|
|
|
|
fn main() {
|
|
let json = fs::read_to_string("fixtures/half_braid.json")
|
|
.expect("Failed to read half_braid.json");
|
|
let half_braid = load_homotopy_diagram_n(&json)
|
|
.expect("Failed to parse");
|
|
|
|
println!("=== SCAFFOLD NODE TRACING ===\n");
|
|
|
|
// Time structure of the 3-diagram
|
|
println!("TIME STRUCTURE (coord[2]):");
|
|
println!(" The half_braid has {} cospan(s)", half_braid.cospans.len());
|
|
println!(" Time heights: r0 (source), s0 (merge), r1 (target)");
|
|
println!();
|
|
|
|
// Source 2-diagram heights
|
|
if let Diagram::DiagramN(src) = half_braid.source() {
|
|
println!("SOURCE 2-DIAGRAM (at time r0):");
|
|
println!(" {} cospans → heights: r0, s0, r1, s1, r2", src.cospans.len());
|
|
println!(" Y-mapping: r0→-1, s0→0, r1→0, s1→1, r2→+1");
|
|
println!();
|
|
}
|
|
|
|
// Target 2-diagram heights
|
|
let target = half_braid.target();
|
|
if let Diagram::DiagramN(tgt) = &target {
|
|
println!("TARGET 2-DIAGRAM (at time r1):");
|
|
println!(" {} cospan(s) → heights: r0, s0, r1", tgt.cospans.len());
|
|
println!(" Y-mapping: r0→-1, s0→0, r1→0");
|
|
println!();
|
|
}
|
|
|
|
println!("=== HEIGHT MAPPING THROUGH MERGE ===");
|
|
println!();
|
|
println!("The merge contracts source heights to target heights:");
|
|
println!(" Source r0 → Target r0 (preserved, y stays at -1)");
|
|
println!(" Source s0 → Target s0 (merges, y=0 → y=0)");
|
|
println!(" Source r1 → Target s0 (absorbed into merge, y=0 → y=0)");
|
|
println!(" Source s1 → Target s0 (merges, y=1 → y=0)");
|
|
println!(" Source r2 → Target r1 (contracts down, y=+1 → y=0)");
|
|
println!();
|
|
|
|
println!("=== SCAFFOLD NODE POSITIONS FOR EACH WIRE ===");
|
|
println!();
|
|
println!("Time positions: r0 at x=-1, s0 at x=0, r1 at x=+1");
|
|
println!("Depth positions: r0→z=-1, r1→z=0, r2→z=+1");
|
|
println!();
|
|
|
|
// Wire r0
|
|
println!("WIRE r0 (coord[0]=r0, depth z=-1):");
|
|
println!(" At time r0 (source): coord=(r0, r0, r0)");
|
|
println!(" → coord[1]=r0=Regular(0) → y = -1");
|
|
println!(" → position: (-1, -1, -1)");
|
|
println!();
|
|
println!(" At time s0 (merge): coord=(r0, s0, s0)");
|
|
println!(" → coord[1]=s0=Singular(0) → y = 0");
|
|
println!(" → position: (0, 0, -1)");
|
|
println!();
|
|
println!(" At time r1 (target): coord=(r0, r0, r1)");
|
|
println!(" → coord[1]=r0=Regular(0) → y = -1");
|
|
println!(" → position: (+1, -1, -1)");
|
|
println!();
|
|
println!(" Wire r0 polyline: [(-1,-1,-1), (0,0,-1), (+1,-1,-1)]");
|
|
println!(" Shape: DIPS to merge, returns to original height");
|
|
println!();
|
|
|
|
// Wire r1
|
|
println!("WIRE r1 (coord[0]=r1, depth z=0):");
|
|
println!(" At time r0 (source): coord=(r1, r1, r0)");
|
|
println!(" → coord[1]=r1=Regular(1) → y = 0");
|
|
println!(" → position: (-1, 0, 0)");
|
|
println!();
|
|
println!(" At time s0 (merge): coord=(r1, s0, s0)");
|
|
println!(" → coord[1]=s0=Singular(0) → y = 0");
|
|
println!(" → position: (0, 0, 0)");
|
|
println!();
|
|
println!(" At time r1 (target): coord=(r1, s0, r1)");
|
|
println!(" → coord[1]=s0=Singular(0) → y = 0 (r1 absorbed into s0)");
|
|
println!(" → position: (+1, 0, 0)");
|
|
println!();
|
|
println!(" Wire r1 polyline: [(-1,0,0), (0,0,0), (+1,0,0)]");
|
|
println!(" Shape: FLAT at y=0 throughout - this is the STEM");
|
|
println!();
|
|
|
|
// Wire r2
|
|
println!("WIRE r2 (coord[0]=r2, depth z=+1):");
|
|
println!(" At time r0 (source): coord=(r2, r2, r0)");
|
|
println!(" → coord[1]=r2=Regular(2) → y = +1");
|
|
println!(" → position: (-1, +1, +1)");
|
|
println!();
|
|
println!(" At time s0 (merge): coord=(r2, s0, s0)");
|
|
println!(" → coord[1]=s0=Singular(0) → y = 0");
|
|
println!(" → position: (0, 0, +1)");
|
|
println!();
|
|
println!(" At time r1 (target): coord=(r2, r1, r1)");
|
|
println!(" → coord[1]=r1=Regular(1) → y = 0 (r2 contracted to r1)");
|
|
println!(" → position: (+1, 0, +1)");
|
|
println!();
|
|
println!(" Wire r2 polyline: [(-1,+1,+1), (0,0,+1), (+1,0,+1)]");
|
|
println!(" Shape: DROPS from y=+1 to y=0, stays at y=0");
|
|
println!();
|
|
|
|
println!("=== SUMMARY ===");
|
|
println!();
|
|
println!("Wire r0: [(-1,-1,-1), (0,0,-1), (1,-1,-1)] // dips and returns");
|
|
println!("Wire r1: [(-1, 0, 0), (0,0, 0), (1, 0, 0)] // flat stem");
|
|
println!("Wire r2: [(-1,+1,+1), (0,0,+1), (1, 0,+1)] // drops and stays");
|
|
}
|