pub trait IndexLike:
Clone
+ Eq
+ Hash
+ Debug
+ Send
+ Sync
+ 'static {
type Id: Clone + Eq + Hash + Debug + Send + Sync;
// Required methods
fn id(&self) -> &Self::Id;
fn dim(&self) -> usize;
fn conj_state(&self) -> ConjState;
fn conj(&self) -> Self;
fn sim(&self) -> Self
where Self: Sized;
fn create_dummy_link_pair() -> (Self, Self)
where Self: Sized;
// Provided methods
fn plev(&self) -> i64 { ... }
fn is_contractable(&self, other: &Self) -> bool { ... }
fn same_id(&self, other: &Self) -> bool { ... }
fn has_id(&self, id: &Self::Id) -> bool { ... }
}Expand description
Trait for index-like types that can be used in tensor operations.
This trait abstracts away the identity mechanism of indices, allowing algorithms to work with any index type that provides equality, hashing, and dimension access.
§Design Principles
Idas associated type: Lightweight identifier (conjugate-independent)Eqby object equality: Two indices are equal iff they represent the same object (including ID, dimension, and conjugate state if applicable)dim(): Returns the dimension of the indexconj_state(): Returns the conjugate state (direction) of the index
§Key Properties
Eq: Defines object equality (includes ID, dimension, and conjugate state)Hash: Enables efficient lookup inHashMap<I, ...>/HashSet<I>Clone: Indices are small value types, freely copyableis_contractable(): Determines if two indices can be contracted
§Conjugate State and Contractability
The conj_state() method returns the direction of an index:
Undirected: Directionless index (ITensors.jl-like default)Ket: Ingoing index (QSpace: no trailing*in itag)Bra: Outgoing index (QSpace: trailing*in itag)
Two indices are contractable if:
- They have the same
id()anddim() - Their conjugate states are compatible:
(Ket, Bra)or(Bra, Ket)→ contractable(Undirected, Undirected)→ contractable- Mixed
(Undirected, Ket/Bra)→ not contractable (mixing forbidden)
§Example
fn contract_common<I: IndexLike>(a: &Tensor<I>, b: &Tensor<I>) -> Tensor<I> {
// Algorithm doesn't need to know about Id, Symm, Tags
// It only needs indices to be comparable and have dimensions
let common: Vec<_> = a.indices().iter()
.filter(|idx| b.indices().contains(idx))
.cloned()
.collect();
// ...
}Required Associated Types§
Sourcetype Id: Clone + Eq + Hash + Debug + Send + Sync
type Id: Clone + Eq + Hash + Debug + Send + Sync
Lightweight identifier type (conjugate-independent).
Rule: Contractable indices must have the same ID.
The ID serves as a “pairing key” to identify which legs are intended to contract. In large tensor networks, IDs enable efficient graph-based lookups (O(1) with HashSet/HashMap) to find matching legs across many tensors.
This is separate from dimension/direction checks:
- ID: “intent to pair” (which specific legs should connect)
- dim/ConjState: “mathematical compatibility” (can they actually contract)
Required Methods§
Sourcefn id(&self) -> &Self::Id
fn id(&self) -> &Self::Id
Get the identifier of this index.
The ID is used as the pairing key during contraction.
Contractable indices must have the same ID — this is enforced by is_contractable().
Two indices with the same ID represent the same logical leg (though they may differ in conjugate state for directed indices).
Sourcefn conj_state(&self) -> ConjState
fn conj_state(&self) -> ConjState
Get the conjugate state (direction) of this index.
Returns ConjState::Undirected for directionless indices (ITensors.jl-like default),
or ConjState::Ket/ConjState::Bra for directed indices (QSpace-compatible).
Sourcefn conj(&self) -> Self
fn conj(&self) -> Self
Create the conjugate of this index.
For directed indices, this toggles between Ket and Bra.
For Undirected indices, this returns self unchanged (no-op).
§Returns
A new index with the conjugate state toggled (if directed) or unchanged (if undirected).
Sourcefn sim(&self) -> Selfwhere
Self: Sized,
fn sim(&self) -> Selfwhere
Self: Sized,
Create a similar index with a new identity but the same structure (dimension, tags, etc.).
This is used to create “equivalent” indices that have the same properties but different identities, commonly needed in index replacement operations.
§Returns
A new index with a fresh identity and the same structure as self.
Sourcefn create_dummy_link_pair() -> (Self, Self)where
Self: Sized,
fn create_dummy_link_pair() -> (Self, Self)where
Self: Sized,
Create a pair of contractable dummy indices with dimension 1.
These are used for structural connections that don’t carry quantum numbers, such as connecting components in a tree tensor network.
Both indices will be Undirected and have the same ID, making them contractable.
§Returns
A pair (idx1, idx2) where idx1.is_contractable(&idx2) is true.
Provided Methods§
Sourcefn is_contractable(&self, other: &Self) -> bool
fn is_contractable(&self, other: &Self) -> bool
Check if this index can be contracted with another index.
Two indices are contractable if:
- They have the same
id()anddim() - Their conjugate states are compatible:
(Ket, Bra)or(Bra, Ket)→ contractable(Undirected, Undirected)→ contractable- Mixed
(Undirected, Ket/Bra)→ not contractable (mixing forbidden)
§Default Implementation
The default implementation checks:
- Same ID:
self.id() == other.id() - Same dimension:
self.dim() == other.dim() - Same prime level:
self.plev() == other.plev() - Compatible conjugate states (see rules above)
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.