IndexLike

Trait IndexLike 

Source
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

  • Id as associated type: Lightweight identifier (conjugate-independent)
  • Eq by 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 index
  • conj_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 in HashMap<I, ...> / HashSet<I>
  • Clone: Indices are small value types, freely copyable
  • is_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() and dim()
  • 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§

Source

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§

Source

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).

Source

fn dim(&self) -> usize

Get the total dimension (state-space dimension) of the index.

Source

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).

Source

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).

Source

fn sim(&self) -> Self
where 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.

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§

Source

fn plev(&self) -> i64

Get the prime level of this index. Default: 0 (unprimed).

Source

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() and dim()
  • 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:

  1. Same ID: self.id() == other.id()
  2. Same dimension: self.dim() == other.dim()
  3. Same prime level: self.plev() == other.plev()
  4. Compatible conjugate states (see rules above)
Source

fn same_id(&self, other: &Self) -> bool

Check if this index has the same ID as another.

Default implementation compares IDs directly. This is a convenience method for pure ID comparison (does not check contractability).

Source

fn has_id(&self, id: &Self::Id) -> bool

Check if this index has the given ID.

Default implementation compares with the given ID.

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.

Implementors§