ariadnetor_tensor/block_sparse/qn_index.rs
1//! `QNIndex<S>`: per-leg quantum-number index with sorted sector blocks.
2
3use super::Direction;
4use crate::sector::Sector;
5
6/// Quantum-number index for one tensor leg.
7///
8/// Maps each sector to a block dimension, with a direction for flux computation.
9///
10/// # Invariants (enforced by constructor)
11///
12/// - `blocks` is sorted by sector (`Ord`)
13/// - No duplicate sectors
14/// - Every block dimension is > 0
15#[derive(Clone, Debug)]
16pub struct QNIndex<S: Sector> {
17 /// Sector → block dimension pairs, sorted by sector, no duplicates.
18 blocks: Vec<(S, usize)>,
19 /// Leg direction.
20 direction: Direction,
21}
22
23impl<S: Sector> QNIndex<S> {
24 /// Create a new QN index.
25 ///
26 /// `blocks` is sorted by sector. Panics if any block dimension is zero
27 /// or if duplicate sectors are present.
28 pub fn new(mut blocks: Vec<(S, usize)>, direction: Direction) -> Self {
29 blocks.sort_by(|a, b| a.0.cmp(&b.0));
30
31 for (i, (sector, dim)) in blocks.iter().enumerate() {
32 assert!(
33 *dim > 0,
34 "QNIndex: block dimension must be > 0 for sector {sector:?}"
35 );
36 if i > 0 {
37 assert!(
38 blocks[i - 1].0 != *sector,
39 "QNIndex: duplicate sector {sector:?}"
40 );
41 }
42 }
43
44 Self { blocks, direction }
45 }
46
47 /// Sector–dimension pairs (sorted by sector).
48 pub fn blocks(&self) -> &[(S, usize)] {
49 &self.blocks
50 }
51
52 /// Leg direction.
53 pub fn direction(&self) -> Direction {
54 self.direction
55 }
56
57 /// Number of distinct sectors (blocks) in this index.
58 pub fn num_blocks(&self) -> usize {
59 self.blocks.len()
60 }
61
62 /// Total dimension (sum of all block dimensions).
63 pub fn total_dim(&self) -> usize {
64 self.blocks.iter().map(|(_, d)| d).sum()
65 }
66
67 /// Block dimension for a given block index.
68 ///
69 /// Panics if `idx >= self.num_blocks()`.
70 pub fn block_dim(&self, idx: usize) -> usize {
71 self.blocks[idx].1
72 }
73
74 /// Sector for a given block index.
75 ///
76 /// Panics if `idx >= self.num_blocks()`.
77 pub fn sector(&self, idx: usize) -> &S {
78 &self.blocks[idx].0
79 }
80}