|
Uni20
Asynchronous tensor and runtime library.
|
Status: active architecture informed by the separate TensorContraction prototype. Pure Uni20 now has a neutral sparse f(r,a,b,c) plan, a dispatched R/A/B/C operation, and a right-first backend with prepared (B,C) reuse. The backend preserves the packed leaf storage of its operands, covering immediate host storage and single-device CUDA storage. Left-first/hybrid selection, multi-device/MPI placement, and the cost model described below remain future work.
tensor_network::TwoSiteEffectiveHamiltonian uses coordinate-indexed joins over the input-center keys, environments, and MPO sites. Construction snapshots MPO coefficients into a canonical sparse plan:
Duplicate (r,a,b,c) entries are summed and exact-zero coefficients are removed. Coefficients are real or complex field scalars; integer coefficient plans are outside the numerical contraction contract. The sorted key tables retain logical block identity independently of the operands' physical storage order, but their coordinate values are interpreted relative to the symmetry and boundaries for which the plan was constructed. Binding a plan to operands with different symmetry or boundary semantics is a program error. The plan does not retain or compare that metadata on the normal execution path. The selected backend resolves valid keys to storage ordinals and placement during preparation. The logical plan is an execution-order-neutral hypergraph: it contains no left-first, right-first, placement, or communication choice.
Backend selection occurs while the output BlockTensor storage policy remains visible. The current RightFirstRabcBackend derives unique (b,c) groups and evaluates:
Every Y_bc is formed once per application. For a fixed effective Hamiltonian, prepare_rabc_contract validates the block structures, derives the grouping and output order, and allocates every intermediate before the Krylov loop. Repeated applications reuse that schedule and workspace. Distinct intermediates and output blocks use the output storage's synchronous block-batch policy, while each output block's contributions remain serial. Dense contractions retain the operation-specific nested selector, so direct/looped GEMM and reference fallback remain available. A prepared executor is tied to one plan and block structure and must not be invoked concurrently.
rabc_contract is an overwrite operation. Every stored output block is assigned on each invocation; a block with no contributing term is filled with zero because missing symmetry sectors are implicitly zero. A future update operation representing R += ABC would instead preserve such blocks.
This note records the intended Uni20 replacement for the temporary TensorContraction Arranger/Swapper scheduling model.
The Hamiltonian apply used by two-site DMRG has terms of the form:
where:
B is the input two-site center vector.R is the output two-site center vector.B and R have the same block spaces and the same block layout.A is the left environment.C is the right environment.The important scheduling problem is not only the local matrix multiply order. It is deciding where each block lives, which intermediates are worth materializing, and whether communication should happen before or after a local contraction.
The resident EffectiveHamiltonianOperator now bypasses the legacy Arranger::analyzeComputation / compileWorklists / doContraction path by default.
The current deterministic bridge still uses a right-first strategy:
The executor:
R block's current device as the owner for work that contributes to that block;R block with beta = 0 on the first contributing GEMM and uses beta = 1 for later accumulation;stderr and zeros only R blocks that receive no contributions;A, B, and C blocks to the R owner device when needed;B*C intermediates keyed by (device, B block, C block);A*(B*C) into R;This is not the final Uni20 storage model. It still borrows TensorContraction buffer bookkeeping while replacing the R/A/B/C worklist scheduling seam. The resident matvec path no longer exposes the old worklist planner as a runtime selection; profiling and cost-model work should use the deterministic bridge.
The legacy Arranger does not compare left-first and right-first plans.
It effectively implements a right-first strategy:
The code detects repeated (B, C) pairs and materializes reusable intermediates. It can also combine intermediates for repeated (R, A) groups before the final A * intermediate multiply.
This was enough to exercise CUDA/NCCL kernels, but it is not a robust Uni20 design. In particular:
A * B route;Matrix/MatrixFamily handles rather than Uni20 tensor storage.Uni20 should allocate blocks according to the BlockSpace and LocalSpace metadata before constructing a contraction schedule.
Each active dense block should have explicit placement:
For the first U(1) DMRG workflow, the block index comes from the bond BlockSpace and the local physical LocalSpace. A placement policy maps those block indexes to devices/ranks deterministically.
This makes placement part of the logical tensor layout, not a rearrangement pass.
The first serious planner should score two global candidate plans:
For this first version, choose one of these two plan families for the apply. Do not yet mix left-first and right-first on different blocks. A later planner can make that choice per R block or per group of terms.
The cost model should include:
A, B, C, and R blocks are local or remote;R must be sent after local contraction;For a term A * B * C, the local dense costs are:
The actual planner should use exact block dimensions from the term.
There are at least two valid communication strategies.
The first prototype can place environment blocks where the input lives:
This is simple and keeps most local Hamiltonian work near the active Krylov vector block. It also makes the final communication explicit: after contraction, send partial R blocks to their owning rank/device.
The alternative is target-owned contraction:
This avoids communicating partial outputs but may require more input staging.
A future planner should score both choices. It may choose a mixture, especially when environment blocks are much smaller than B/R blocks or when one side of the environment has high reuse.
The left and right environments are cold host/cache tensors when they are not active. During one local solve, active environment blocks should be materialized on GPU according to a placement policy.
For the first placement-first implementation:
B and R blocks from the two-site center BlockSpace;A and C environment blocks on the same rank/device as the corresponding input-side B blocks when possible;R block.This deliberately favors a simple first implementation over a globally optimal communication schedule.
The temporary TensorContraction bridge currently implements only the first local-device placement slice of this idea for resident vector algebra: complete MatrixFamily storage is split into contiguous byte-balanced ranges, with one coalesced device slab per active local GPU. That policy removes the worst per-block Arranger/Swapper overhead in forced all-GPU diagnostics, but it is not yet keyed by BlockSpace, environment ownership, or R/A/B/C term structure.
The resident bridge now keeps only a narrow explicit placement hook while the real planner is being designed. With UNI20_TENSORCONTRACTION_RABC_PLACEMENT=manual, Hamiltonian matvecs use UNI20_TENSORCONTRACTION_RABC_PLACEMENT_LAYOUT as the shared owner layout for the matching B and R center spaces. Environment-style contractions may use separate UNI20_TENSORCONTRACTION_RABC_B_LAYOUT and UNI20_TENSORCONTRACTION_RABC_R_LAYOUT lists because B and R are different spaces. The executor forms each right-first B_b C_c product on owner(B_b) and then accumulates A_a (B_b C_c) on owner(R_r).
The older cost, cost-block, stripe, and empirical-contiguous runtime paths were ordered-range or replay-fit diagnostics. They should not be used as the implementation target: an ordered range only refers to the current block construction order, while the real objective is the sparse f hypergraph.
The placement problem is a graph/hypergraph partitioning problem with execution choices attached to each hyperedge. The sparse TensorContraction f tensor is the ground-truth connectivity object. Its nonzero entries are terms of the form
Each term connects one output block, three input blocks, and one scalar coefficient. Symmetry and fusion rules explain why this sparse f tensor has locality, but they should not replace the f tensor in the planner. For the U(1) Heisenberg Hamiltonian, local terms change charge by 0, +1, or -1. Since the total Hamiltonian is a scalar, a charge-changing left/environment operation must be compensated by the opposite change on the other side. This clusters strongly connected center blocks in neighboring quantum-number sectors. The empirical placement model should therefore read locality from the actual f hypergraph. A one-dimensional ordered-range search is only a legacy diagnostic for checking whether the current construction order happens to cluster connected sectors; it is not a general placement domain.
Use the fixture trace tooling to inspect this connectivity directly:
The summary reports center-block fanout from each B_b, direct (R_r, B_b) connectivity, right-first reuse hyperedges keyed by (B_b, C_c), and left-first reuse hyperedges keyed by (A_a, B_b). These are the graph objects that should feed a real partitioner. A contiguous cutK layout is only a restricted diagnostic over the current block ordering; it is not the general model, especially once multiple symmetries or less one-dimensional fusion structure are present. More strongly, contiguity is a storage property, not a logical invariant: the bond and center block spaces can be permuted, and any chosen partition can be packed into contiguous per-device slabs after the placement decision.
The LaTeX design note docs/latex/rabc_hypergraph_partitioning.tex gives the restricted Hamiltonian-domain formulation in terms of a center owner map, exact left/right temporary factorizations of the sparse f tensor, temporary construction devices, and second-stage execution devices. Under explicit canonical rules, those variables induce the B-block copies, temporary migrations, per-device partial outputs, and final reductions. The same note also records the environment-construction variant, where input and output block owners do not need to coincide.
The more implementation-oriented note docs/latex/rabc_input_anchored_model.tex records the first serious restricted model: B and R share one layout h, the first GEMM for a term runs on h(b), the second GEMM runs on h(r), and the only remaining term-level choice is left-first versus right-first. That anchoring makes the temporary copy schedule and environment staging costs deterministic for a chosen layout and path assignment.
The U(1) Heisenberg chain is useful for low-overhead benchmarking, but it is a weak stress test for the placement model because the dominant sector connectivity is close to one-dimensional in the chosen block ordering. The nearest-neighbor Fermi-Hubbard chain with U(1)xU(1) symmetry is the next reference benchmark: center blocks are labelled by two charges, hopping terms move through distinct up/down charge directions, and the sparse f tensor is a more faithful proxy for the multi-charge hypergraph that the final planner must partition. The default byte-balanced layout or a legacy ordered-range diagnostic may still win for small fixtures, but that should be interpreted as an empirical result for the measured f tensor, not as evidence that a one-dimensional ordering is the general optimization model.
In the final Uni20 model, decision variables should include:
p_F(i) = (rank, device) for each block i in each family F in {A, B, C, R};o_t in {left-first, right-first} for each term or term group;e_g for each materialized intermediate group, for example (B_b, C_c) in a right-first plan;R_r contributions when work is computed away from the final R owner;The objective should minimize the critical path, not the sum of all work:
where load(device) contains:
For the current resident Lanczos fixture benchmark, setup terms are deliberately excluded from the primary objective. The static A and C environments should be placed before timing the Krylov loop. The timed objective is the repeated matrix-free matvec plus the vector-algebra constraints it imposes.
The fully generic term workflow is richer than a single target-owned GEMM pair. For each logical contribution, the planner may need to decide:
R_r and accumulate into the output block.The multiplication order is therefore a per-term or per-group decision, not a global flag. Some moves in this chain may be unnecessary for a specific geometry or cost model, but the planner should include them as possible edges so benchmark feedback can decide which ones are worth scheduling.
The interesting mixed-order case is when different connected regions of the same sparse f hypergraph prefer different first-stage contractions. The planner should eventually compare at least these grouped choices:
(B_b, C_c), computing Y = B_b * C_c;(A_a, B_b), computing X = A_a * B_b;R_r owner.This is where symmetry locality enters constructively. A scalar Hamiltonian term can move charge on one side only if the opposite side compensates it, so the useful groups are determined by the nonzero f entries and the fusion algebra that generated them. The final planner should score mixed left/right groups from that graph rather than choosing one global order for every block.
The local rectangular-block heuristic is simpler: for an isolated term, multiply through the long dimension of the center block B first. If B is tall, the left-first path A * B contracts the long row dimension; if B is wide, the right-first path B * C contracts the long column dimension. This is only a local heuristic. Reuse encoded in the sparse f tensor, communication costs, and shared intermediates can override it, especially when many neighboring sectors share the same (A, B) or (B, C) group.
The right-first, target-owned prototype is the reduced problem:
Its per-device model is:
The former cost, cost-block, stripe, and empirical-contiguous runtime diagnostics have been removed from the C++ bridge. They were useful for learning, but they were runtime policies over ordered block ranges or replay-fit coefficients rather than solvers for the graph problem above. Current experiments should generate candidate layouts offline and replay them as explicit manual layouts. The operator still applies one canonical center-vector layout to both Krylov input and output blocks; if a contraction produces a block away from that canonical owner, the generic planner must account for the relayout before the result becomes the next Lanczos input.
Replay benchmarks still provide useful evidence even though the automatic runtime policies have been removed. On the local Hubbard L=40, m=5000 U(1)xU(1) fixture, a graph-augmented fit over ordered splits selects the measured-good basin historically labelled cut323 to cut326, giving a real two-GPU speedup over the one-GPU baseline. This validates the tracing and replay loop, and it shows that graph-derived features are the right source of placement information.
The same evidence does not yet justify using an unconstrained non-contiguous layout as runtime policy. Direct replays of segmented candidates have not beaten the contiguous basin. The better segmented candidates reduce the right-first or mixed critical-path flops, but they increase peer B traffic and skew terms and unique (B, C) groups onto one device. Unconstrained linear fits can also assign negative weights to correlated communication features, so they are useful for diagnostics and candidate generation but are not a principled graph optimizer.
The next planner target should therefore be a calibrated graph/hypergraph cost function, not simply a larger feature vector. The cost function should use the nonzero f tensor to construct typed edges for compute, communication, duplication, and reduction pressure. Benchmark data should calibrate the weights and overhead terms, while the structural model should preserve monotonic penalties for obviously costly events such as peer traffic, duplicated first-stage groups, output-layout mismatch, and severe device-load skew. Candidate layouts from that cost function must still be replayed before being promoted to a runtime policy.
Current monotonic structural diagnostics support this conclusion. Narrow feature subsets such as execution-pressure, launch-pressure, and no-output produce similar leave-one-layout-out errors and still miss the best observed Hubbard ordered-range basin. This suggests that the missing information is not just which aggregate counters are included, but how typed hyperedges share work, traffic, and launch pressure across candidate partitions.
A first typed-hypergraph diagnostic adds weighted split counters for B fanout, direct (R,B) edges, and right/left first-stage reuse hyperedges. It improves the small overhead fixture, but still misses the Hubbard L=40, m=5000 best ordered-range basin. The next model therefore needs a more explicit execution-state cost over typed hyperedges, not just monotonic penalties on typed split summaries.
Live DMRG validation also shows that fixture-local replay fits are not portable enough to use as a default sweep policy. A graph-augmented fit that selects the near-best historical cut326 layout for the Hubbard L=40, m=5000 central replay fixture loses badly on a live L=30, max_rank=512 sweep: after filtering to States >= 512, matvec time rose from 0.0478421028s to 0.0798366683s per Hamiltonian application. The planner therefore needs either live-shape training data or a structural execution model that generalizes across the changing effective-Hamiltonian block graphs seen during a sweep.
The long-term scheduler should operate on a term graph:
Equivalently, the sparse f tensor defines a finite-state hypergraph partitioning problem. For two GPUs and a fixed canonical center-vector layout, the first split is the B/R owner, giving two parts. Each part can then be subdivided by the first contraction choice, left-first A * B or right-first B * C. Additional binary choices, such as whether to migrate the input center block first, whether to migrate an intermediate, and where to reduce a partial R, multiply the number of execution labels but keep it finite. Once those labels have costs, the planner is a graph or hypergraph partitioner over the nonzero f entries with typed execution states.
It should group terms by reusable pairs:
A dynamic-programming or graph-optimization algorithm can then choose a mixed plan over groups, subject to memory and communication constraints.
The important architectural constraint is that this planner should consume Uni20 device/block abstractions directly. It should not depend on TensorContraction Arranger/Swapper, and it should not rely on implicit host copies or late global rearrangement.