Files
visualizador_instanciados/radial_sugiyama/GO_PIPELINE_INTERSECTION.md
2026-03-23 11:13:27 -03:00

8.0 KiB

Radial Sugiyama vs Go Snapshot Pipeline

This note delimits the algorithmic intersection between the Rust pipeline in radial_sugiyama/ and the Go snapshot/export path in:

  • backend_go/graph_export.go
  • backend_go/graph_snapshot.go

The goal is not to describe integration mechanics yet, but to mark where the two implementations solve the same problem, where they only touch indirectly, and where they are solving different problems.

Scope

The Rust pipeline is a hierarchy-specific layout pipeline:

  1. import ontology hierarchy from Turtle
  2. optionally filter to a rooted descendant subtree
  3. validate DAG structure
  4. assign hierarchy levels
  5. insert dummy nodes for long edges
  6. reduce crossings
  7. assign coordinates
  8. project to radial space
  9. generate routed edge artifacts
  10. export SVG

The Go path is a snapshot/materialization pipeline:

  1. query predicates and edges from SPARQL
  2. accumulate nodes and edges
  3. build a graph response
  4. run a lightweight hierarchy layering + radial placement
  5. attach labels
  6. return JSON to the frontend

Because of that, the true intersection is narrow in graph_export.go and broader in the layout section of graph_snapshot.go.

Legend

  • Direct overlap: both sides implement essentially the same algorithmic concern
  • Adjacent overlap: one side prepares or consumes the same kind of structure, but the algorithm differs materially
  • No overlap: the stage exists only on one side

Intersection with graph_export.go

graph_export.go overlaps with the Rust pipeline only at graph materialization time.

Algorithmic stage Rust pipeline graph_export.go Intersection Notes
Node identity and deduplication ttl.rs maps class IRIs to stable node indices graphAccumulator.getOrAddNode maps SPARQL terms to stable node IDs Direct overlap Both build a unique node set from repeated source records.
Edge materialization ttl.rs emits superclass -> subclass edges and deduplicates repeats graphAccumulator.addBindings emits source -> target edges from SPARQL bindings Adjacent overlap Both convert raw triples/bindings into an in-memory graph, but Rust is specialized to rdfs:subClassOf while Go is predicate-agnostic.
Literal / blank-node filtering ttl.rs ignores blank/literal hierarchy endpoints getOrAddNode skips literals and optionally keeps blank nodes Adjacent overlap Similar sanitation step, but not identical semantics.
Predicate preservation Rust discards all predicates except rdfs:subClassOf Go preserves predicate IDs through PredicateDict No overlap This is Go-only in the compared files.
Graph limits / capacity management Rust does not enforce snapshot-style node and edge caps here Go enforces nodeLimit and preallocates with edge hints No overlap This is an operational concern of the Go snapshot path.

Boundary for graph_export.go

The clean algorithmic seam is:

  • Go owns generic SPARQL binding ingestion and generic graph materialization.
  • Rust owns hierarchy-specialized interpretation once a hierarchy graph has already been isolated.

That means graph_export.go is not competing with the Rust layout pipeline. It is only producing the kind of node/edge structure that Rust would eventually need as input.

Intersection with graph_snapshot.go

graph_snapshot.go intersects with the Rust pipeline in two different regions:

  1. graph acquisition and hierarchy preparation
  2. lightweight layout assignment

Stage-by-stage comparison

Algorithmic stage Rust pipeline graph_snapshot.go Intersection Notes
Source acquisition graph_from_ttl_path parses Turtle directly fetchGraphSnapshot queries SPARQL in batches Adjacent overlap Both acquire a graph, but from different upstream sources.
Hierarchy graph extraction Rust keeps only rdfs:subClassOf during import Go accepts a graph_query_id and accumulates whatever that query returns Adjacent overlap The overlap is meaningful only when the Go query is hierarchy-like.
Rooted subtree filtering filter_graph_to_descendants keeps one configured root and its descendants No equivalent in these two Go files No overlap This is currently Rust-only.
Cycle detection / DAG validation compute_hierarchy_levels rejects cyclic graphs levelSynchronousKahnLayers returns a CycleError if not all nodes are processed Direct overlap Both need a DAG to continue with hierarchy layout.
Level assignment Rust computes longest-path hierarchy levels Go computes level-synchronous Kahn layers Direct overlap Same problem, different algorithm. Both assign ring depth from DAG structure.
Per-level ordering Rust later optimizes order for crossings Go sorts each layer lexicographically by IRI Adjacent overlap Both define an order inside a level, but Go is a simple deterministic ordering while Rust is layout-driven.
Radial node placement Rust projects coordinates to rings after Sugiyama coordinate assignment Go uses radialPositionsFromLayers to place each layer on a ring Direct overlap Same output shape, very different sophistication.
Coordinate shifting / scaling controls Rust has configurable radius, spacing, borders, and positive-coordinate shifting Go uses a fixed maxR = 5000.0 radial envelope Adjacent overlap Both map levels to 2D coordinates, but only Rust exposes tuned geometry controls.
Label enrichment Rust keeps node labels as imported IRIs Go fetches rdfs:label after layout Adjacent overlap Both carry node naming, but the enrichment algorithm is currently Go-only.
Response packaging Rust writes SVG and layout artifacts Go returns GraphResponse JSON plus metadata No overlap Same graph, different downstream consumers.

Rust-only algorithms with no counterpart in the compared Go files

These parts of the Rust pipeline do not currently intersect with graph_export.go or graph_snapshot.go:

  • rooted descendant filtering
  • dummy-node insertion for long edges
  • crossing reduction / sifting
  • coordinate assignment before radial projection
  • adaptive / packed / distributed ring projection modes
  • routed edge generation
  • layout artifact generation
  • SVG rendering and export

These are the parts that make the Rust pipeline a true Sugiyama-style layout engine rather than a simple radial snapshot placer.

Go-only algorithms with no counterpart in the Rust pipeline

These parts of the compared Go files do not currently exist in Rust:

  • predicate dictionary construction from SPARQL results
  • batched SPARQL edge fetching with memory management
  • snapshot limits and backend metadata packaging
  • rdfs:label lookup through SPARQL
  • generic graph export over arbitrary predicate sets

These are acquisition and serving concerns rather than layout concerns.

Algorithmic ownership boundary

If the future integration wants a clean division of responsibility, the strongest ownership boundary is:

Go-owned stages

  • query execution against AnzoGraph / SPARQL
  • predicate-aware graph accumulation
  • generic graph snapshot materialization
  • label fetching and API response orchestration

Rust-owned stages

  • hierarchy-specific filtering
  • hierarchy-level assignment
  • Sugiyama expansion with dummy nodes
  • crossing minimization
  • coordinate assignment
  • radial projection and route generation
  • layout artifact production

Most important practical conclusion

At algorithm granularity, the Rust pipeline intersects only lightly with graph_export.go, but it intersects substantially with the hierarchy-layout portion of graph_snapshot.go.

The main replacement candidates in a future integration are therefore not the generic export/materialization routines in graph_export.go, but these hierarchy-layout steps currently performed by graph_snapshot.go:

  1. DAG validation / cycle detection
  2. layer assignment
  3. per-layer ordering
  4. radial coordinate generation

Everything after that depends on how much of the Rust layout artifact model the future integration wants to expose to the frontend.