Skip to main content

TensorTrain

Struct TensorTrain 

Source
pub struct TensorTrain { /* private fields */ }
Expand description

Tensor Train with orthogonality tracking.

This type represents a tensor train as a sequence of tensors with tracked orthogonality limits. It is inspired by ITensorMPS.jl but uses 0-indexed sites (Rust convention).

Unlike traditional MPS which assumes one physical index per site, this implementation allows each site to have multiple site indices.

§Orthogonality Tracking

The tensor train tracks orthogonality using ortho_region from the underlying TreeTN:

  • When ortho_region is empty, no orthogonality is assumed
  • When ortho_region contains a single site, that site is the orthogonality center

§Implementation

Internally wraps TreeTN<TensorDynLen, usize> where node names are site indices. This allows reuse of TreeTN’s canonicalization and contraction algorithms.

§Examples

Build a 2-site tensor train and query its properties:

use tensor4all_itensorlike::TensorTrain;
use tensor4all_core::{DynIndex, TensorDynLen, Index};
use tensor4all_core::DynId;

// Site indices and link index
let s0 = Index::new_with_size(DynId(0), 2);
let link = Index::new_with_size(DynId(1), 3);
let s1 = Index::new_with_size(DynId(2), 2);

let t0 = TensorDynLen::from_dense(
    vec![s0.clone(), link.clone()],
    (0..6).map(|i| i as f64).collect(),
).unwrap();
let t1 = TensorDynLen::from_dense(
    vec![link.clone(), s1.clone()],
    (0..6).map(|i| i as f64).collect(),
).unwrap();

let tt = TensorTrain::new(vec![t0, t1]).unwrap();
assert_eq!(tt.len(), 2);
assert_eq!(tt.maxbonddim(), 3);
assert!(!tt.is_empty());

Implementations§

Source§

impl TensorTrain

Source

pub fn contract(&self, other: &Self, options: &ContractOptions) -> Result<Self>

Contract two tensor trains, returning a new tensor train.

This performs element-wise contraction of corresponding sites, similar to MPO-MPO contraction in ITensor.

§Arguments
  • other - The other tensor train to contract with
  • options - Contraction options (method, max_rank, rtol, nhalfsweeps)
§Returns

A new tensor train resulting from the contraction.

§Errors

Returns an error if:

  • Either tensor train is empty
  • The tensor trains have different lengths
  • The contraction algorithm fails
Source§

impl TensorTrain

Source

pub fn linsolve( &self, rhs: &Self, init: Self, options: &LinsolveOptions, ) -> Result<Self>

Solve (a₀ + a₁ * A) * x = b for x.

self is the operator A, rhs is b, init is the initial guess.

See linsolve for details.

Source§

impl TensorTrain

Source

pub fn new(tensors: Vec<TensorDynLen>) -> Result<Self>

Create a new tensor train from a vector of tensors.

The tensor train is created with no assumed orthogonality.

§Arguments
  • tensors - Vector of tensors representing the tensor train
§Returns

A new tensor train with no orthogonality.

§Errors

Returns an error if the tensors have inconsistent bond dimensions (i.e., the link indices between adjacent tensors don’t match).

Source

pub fn with_ortho( tensors: Vec<TensorDynLen>, llim: i32, rlim: i32, canonical_form: Option<CanonicalForm>, ) -> Result<Self>

Create a new tensor train with specified orthogonality center.

This is useful when constructing a tensor train that is already in canonical form.

§Arguments
  • tensors - Vector of tensors representing the tensor train
  • llim - Left orthogonality limit (for compatibility; only used to compute center)
  • rlim - Right orthogonality limit (for compatibility; only used to compute center)
  • canonical_form - The method used for canonicalization (if any)
Source

pub fn len(&self) -> usize

Number of sites (tensors) in the tensor train.

Source

pub fn is_empty(&self) -> bool

Check if the tensor train is empty.

Source

pub fn llim(&self) -> i32

Left orthogonality limit.

Sites 0..llim are guaranteed to be left-orthogonal. Returns -1 if no sites are left-orthogonal.

Source

pub fn rlim(&self) -> i32

Right orthogonality limit.

Sites rlim..len() are guaranteed to be right-orthogonal. Returns len() + 1 if no sites are right-orthogonal.

Source

pub fn set_llim(&mut self, llim: i32)

Set the left orthogonality limit.

Source

pub fn set_rlim(&mut self, rlim: i32)

Set the right orthogonality limit.

Source

pub fn ortho_lims(&self) -> Range<usize>

Get the orthogonality center range.

Returns the range of sites that may not be orthogonal. If the tensor train is fully left-orthogonal, returns an empty range at the end. If the tensor train is fully right-orthogonal, returns an empty range at the beginning.

Source

pub fn isortho(&self) -> bool

Check if the tensor train has a single orthogonality center.

Returns true if there is exactly one site that is not guaranteed to be orthogonal.

Source

pub fn orthocenter(&self) -> Option<usize>

Get the orthogonality center (0-indexed).

Returns Some(site) if the tensor train has a single orthogonality center, None otherwise.

Source

pub fn canonical_form(&self) -> Option<CanonicalForm>

Get the canonicalization method used.

Source

pub fn set_canonical_form(&mut self, method: Option<CanonicalForm>)

Set the canonicalization method.

Source

pub fn tensor(&self, site: usize) -> &TensorDynLen

Get a reference to the tensor at the given site.

§Panics

Panics if site >= len().

Source

pub fn tensor_checked(&self, site: usize) -> Result<&TensorDynLen>

Get a reference to the tensor at the given site.

Returns Err if site >= len().

Source

pub fn tensor_mut(&mut self, site: usize) -> &mut TensorDynLen

Get a mutable reference to the tensor at the given site.

§Panics

Panics if site >= len().

Source

pub fn tensors(&self) -> Vec<&TensorDynLen>

Get a reference to all tensors.

Source

pub fn tensors_mut(&mut self) -> Vec<&mut TensorDynLen>

Get a mutable reference to all tensors.

Source

pub fn linkind(&self, i: usize) -> Option<DynIndex>

Get the link index between sites i and i+1.

Returns None if i >= len() - 1 or if no common index exists.

Source

pub fn linkinds(&self) -> Vec<DynIndex>

Get all link indices.

Returns a vector of length len() - 1 containing the link indices.

Source

pub fn sim_linkinds(&self) -> Self

Create a copy with all link indices replaced by new unique IDs.

This is useful for computing inner products where two tensor trains share link indices. By simulating (replacing) the link indices in one of the tensor trains, they can be contracted over site indices only.

Source

pub fn siteinds(&self) -> Vec<Vec<DynIndex>>

Get the site indices (non-link indices) for all sites.

For each site, returns a vector of indices that are not shared with adjacent tensors (i.e., the “physical” or “site” indices).

Source

pub fn bond_dim(&self, i: usize) -> Option<usize>

Get the bond dimension at link i (between sites i and i+1).

Returns None if i >= len() - 1.

Source

pub fn bond_dims(&self) -> Vec<usize>

Get all bond dimensions.

Returns a vector of length len() - 1.

Source

pub fn maxbonddim(&self) -> usize

Get the maximum bond dimension.

Check if two adjacent tensors share an index.

Source

pub fn set_tensor(&mut self, site: usize, tensor: TensorDynLen)

Replace the tensor at the given site.

This invalidates orthogonality tracking.

Source

pub fn orthogonalize(&mut self, site: usize) -> Result<()>

Orthogonalize the tensor train to have orthogonality center at the given site.

This function performs a series of factorizations to make the tensor train canonical with orthogonality center at site.

§Arguments
  • site - The target site for the orthogonality center (0-indexed)
§Errors

Returns an error if the factorization fails or if the site is out of bounds.

§Examples
use tensor4all_itensorlike::TensorTrain;
use tensor4all_core::{DynIndex, TensorDynLen, Index, DynId};

let s0 = Index::new_with_size(DynId(0), 2);
let link = Index::new_with_size(DynId(1), 3);
let s1 = Index::new_with_size(DynId(2), 2);

let t0 = TensorDynLen::from_dense(
    vec![s0.clone(), link.clone()],
    (0..6).map(|i| i as f64).collect(),
).unwrap();
let t1 = TensorDynLen::from_dense(
    vec![link.clone(), s1.clone()],
    (0..6).map(|i| i as f64).collect(),
).unwrap();

let mut tt = TensorTrain::new(vec![t0, t1]).unwrap();
assert!(!tt.isortho());

// Orthogonalize to site 0
tt.orthogonalize(0).unwrap();
assert!(tt.isortho());
assert_eq!(tt.orthocenter(), Some(0));
Source

pub fn orthogonalize_with( &mut self, site: usize, form: CanonicalForm, ) -> Result<()>

Orthogonalize with a specified canonical form.

§Arguments
  • site - The target site for the orthogonality center (0-indexed)
  • form - The canonical form to use:
    • Unitary: Uses QR decomposition, each tensor is isometric
    • LU: Uses LU decomposition, one factor has unit diagonal
    • CI: Uses Cross Interpolation
Source

pub fn truncate(&mut self, options: &TruncateOptions) -> Result<()>

Truncate the tensor train bond dimensions.

This delegates to the TreeTN’s truncate_mut method, which performs a two-site sweep with Euler tour traversal for optimal truncation.

Note: The site_range option in TruncateOptions is currently ignored as the underlying TreeTN truncation operates on the full network.

§Examples
use tensor4all_itensorlike::{TensorTrain, TruncateOptions};
use tensor4all_core::{DynIndex, TensorDynLen, Index, DynId};

// Build a 3-site tensor train with bond dimension 4
let s0 = Index::new_with_size(DynId(0), 2);
let l01 = Index::new_with_size(DynId(1), 4);
let s1 = Index::new_with_size(DynId(2), 2);
let l12 = Index::new_with_size(DynId(3), 4);
let s2 = Index::new_with_size(DynId(4), 2);

let t0 = TensorDynLen::from_dense(
    vec![s0.clone(), l01.clone()],
    (0..8).map(|i| i as f64).collect(),
).unwrap();
let t1 = TensorDynLen::from_dense(
    vec![l01.clone(), s1.clone(), l12.clone()],
    (0..32).map(|i| i as f64).collect(),
).unwrap();
let t2 = TensorDynLen::from_dense(
    vec![l12.clone(), s2.clone()],
    (0..8).map(|i| i as f64).collect(),
).unwrap();

let mut tt = TensorTrain::new(vec![t0, t1, t2]).unwrap();
assert_eq!(tt.maxbonddim(), 4);

// Truncate bond dimension to at most 2
let opts = TruncateOptions::svd().with_max_rank(2);
tt.truncate(&opts).unwrap();
assert!(tt.maxbonddim() <= 2);
Source

pub fn inner(&self, other: &Self) -> AnyScalar

Compute the inner product (dot product) of two tensor trains.

Computes <self | other> = sum over all indices of conj(self) * other.

Both tensor trains must have the same site indices (same IDs). Link indices may differ between the two tensor trains.

§Examples
use tensor4all_itensorlike::TensorTrain;
use tensor4all_core::{DynIndex, TensorDynLen, Index, DynId, AnyScalar};

// Single-site tensor train with values [1.0, 0.0]
let s0 = Index::new_with_size(DynId(0), 2);
let t = TensorDynLen::from_dense(
    vec![s0.clone()],
    vec![1.0_f64, 0.0],
).unwrap();

let tt = TensorTrain::new(vec![t]).unwrap();

// <tt | tt> = 1.0^2 + 0.0^2 = 1.0
let result = tt.inner(&tt);
assert!((result.real() - 1.0).abs() < 1e-10);
Source

pub fn norm_squared(&self) -> f64

Compute the squared norm of the tensor train.

Returns <self | self> = ||self||^2.

§Note

For linear tensor trains with one site index per site, this uses a specialized chain contraction instead of the generic inner-product path. Due to numerical errors, the final scalar can be very slightly negative, so the returned value is clamped to be non-negative.

Source

pub fn norm(&self) -> f64

Compute the norm of the tensor train.

Returns ||self|| = sqrt(<self | self>).

Source

pub fn to_dense(&self) -> Result<TensorDynLen>

Convert the tensor train to a single dense tensor.

This contracts all tensors in the train along their link indices, producing a single tensor with only site indices.

§Warning

This operation can be very expensive for large tensor trains, as the result size grows exponentially with the number of sites.

§Returns

A single tensor containing all site indices, or an error if the tensor train is empty.

§Example
use tensor4all_core::{DynIndex, TensorDynLen};
use tensor4all_itensorlike::TensorTrain;

let s0 = DynIndex::new_dyn(2);
let link = DynIndex::new_dyn(1);
let s1 = DynIndex::new_dyn(2);
let t0 = TensorDynLen::from_dense(vec![s0.clone(), link.clone()], vec![1.0, 2.0])?;
let t1 = TensorDynLen::from_dense(vec![link.clone(), s1.clone()], vec![3.0, 4.0])?;

let tt = TensorTrain::new(vec![t0, t1])?;
let dense = tt.to_dense()?;

assert_eq!(dense.dims(), vec![2, 2]);
assert_eq!(dense.to_vec::<f64>()?, vec![3.0, 6.0, 4.0, 8.0]);
Source

pub fn add(&self, other: &Self) -> Result<Self>

Add two tensor trains using direct-sum construction.

This creates a new tensor train where each tensor is the direct sum of the corresponding tensors from self and other, with bond dimensions merged. The result has bond dimensions equal to the sum of the input bond dimensions.

§Arguments
  • other - The other tensor train to add
§Returns

A new tensor train representing the sum.

§Errors

Returns an error if the tensor trains have incompatible structures.

Source

pub fn scale(&self, scalar: AnyScalar) -> Result<Self>

Scale the tensor train by a scalar.

Only one tensor (the first non-empty site) is scaled to avoid scalar^n scaling. This is correct because the tensor train represents a product of tensors, so scaling one factor scales the entire product.

§Arguments
  • scalar - The scalar to multiply by
§Returns

A new tensor train scaled by the given scalar.

§Example
use tensor4all_core::{AnyScalar, DynIndex, TensorDynLen};
use tensor4all_itensorlike::TensorTrain;

let s0 = DynIndex::new_dyn(2);
let tt = TensorTrain::new(vec![TensorDynLen::from_dense(
    vec![s0.clone()],
    vec![1.0, 2.0],
)?])?;

let scaled = tt.scale(AnyScalar::new_real(2.0))?;
assert_eq!(scaled.to_dense()?.to_vec::<f64>()?, vec![2.0, 4.0]);
Source

pub fn axpby(&self, a: AnyScalar, other: &Self, b: AnyScalar) -> Result<Self>

Compute a linear combination: a * self + b * other.

This is equivalent to self.scale(a)?.add(&other.scale(b)?).

§Arguments
  • a - Scalar coefficient for self
  • other - The other tensor train
  • b - Scalar coefficient for other
§Returns

A new tensor train representing a * self + b * other.

§Note

The bond dimension of the result is the sum of the bond dimensions of the two input tensor trains (before any truncation).

Trait Implementations§

Source§

impl Clone for TensorTrain

Source§

fn clone(&self) -> TensorTrain

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TensorTrain

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TensorTrain

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl TensorIndex for TensorTrain

Source§

type Index = Index<DynId>

The index type used by this object.
Source§

fn external_indices(&self) -> Vec<Self::Index>

Return flattened external indices for this object. Read more
Source§

fn num_external_indices(&self) -> usize

Number of external indices. Read more
Source§

fn replaceind(&self, old: &Self::Index, new: &Self::Index) -> Result<Self>

Replace an index in this object. Read more
Source§

fn replaceinds(&self, old: &[Self::Index], new: &[Self::Index]) -> Result<Self>

Replace multiple indices in this object. Read more
Source§

fn replaceinds_pairs( &self, pairs: &[(Self::Index, Self::Index)], ) -> Result<Self, Error>

Replace indices using pairs of (old, new). Read more
Source§

impl TensorLike for TensorTrain

Source§

fn axpby(&self, a: AnyScalar, other: &Self, b: AnyScalar) -> Result<Self>

Compute a linear combination: a * self + b * other. Read more
Source§

fn scale(&self, scalar: AnyScalar) -> Result<Self>

Scalar multiplication.
Source§

fn inner_product(&self, other: &Self) -> Result<AnyScalar>

Inner product (dot product) of two tensors. Read more
Source§

fn norm_squared(&self) -> f64

Compute the squared Frobenius norm of the tensor. Read more
Source§

fn maxabs(&self) -> f64

Maximum absolute value of all elements (L-infinity norm).
Source§

fn conj(&self) -> Self

Tensor conjugate operation. Read more
Source§

fn factorize( &self, _left_inds: &[Self::Index], _options: &FactorizeOptions, ) -> Result<FactorizeResult<Self>, FactorizeError>

Factorize this tensor into left and right factors. Read more
Source§

fn contract(_tensors: &[&Self], _allowed: AllowedPairs<'_>) -> Result<Self>

Contract multiple tensors over their contractable indices. Read more
Source§

fn contract_connected( _tensors: &[&Self], _allowed: AllowedPairs<'_>, ) -> Result<Self>

Contract multiple tensors that must form a connected graph. Read more
Source§

fn direct_sum( &self, _other: &Self, _pairs: &[(Self::Index, Self::Index)], ) -> Result<DirectSumResult<Self>>

Direct sum of two tensors along specified index pairs. Read more
Source§

fn outer_product(&self, _other: &Self) -> Result<Self>

Outer product (tensor product) of two tensors. Read more
Source§

fn permuteinds(&self, _new_order: &[Self::Index]) -> Result<Self>

Permute tensor indices to match the specified order. Read more
Source§

fn diagonal(input: &Self::Index, output: &Self::Index) -> Result<Self>

Create a diagonal (Kronecker delta) tensor for a single index pair. Read more
Source§

fn scalar_one() -> Result<Self>

Create a scalar tensor with value 1.0. Read more
Source§

fn ones(indices: &[Self::Index]) -> Result<Self>

Create a tensor filled with 1.0 for the given indices. Read more
Source§

fn onehot(index_vals: &[(Self::Index, usize)]) -> Result<Self>

Create a one-hot tensor with value 1.0 at the specified index positions. Read more
Source§

fn norm(&self) -> f64

Compute the Frobenius norm of the tensor.
Source§

fn sub(&self, other: &Self) -> Result<Self, Error>

Element-wise subtraction: self - other. Read more
Source§

fn neg(&self) -> Result<Self, Error>

Negate all elements: -self.
Source§

fn isapprox(&self, other: &Self, atol: f64, rtol: f64) -> bool

Approximate equality check (Julia isapprox semantics). Read more
Source§

fn validate(&self) -> Result<(), Error>

Validate structural consistency of this tensor. Read more
Source§

fn delta( input_indices: &[Self::Index], output_indices: &[Self::Index], ) -> Result<Self, Error>

Create a delta (identity) tensor as outer product of diagonals. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<U> As for U

§

fn as_<T>(self) -> T
where T: CastFrom<U>,

Casts self to type T. The semantics of numeric casting with the as operator are followed, so <T as As>::as_::<U> can be used in the same way as T as U for numeric conversions. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> ByRef<T> for T

§

fn by_ref(&self) -> &T

§

impl<T> ByRef<T> for T

§

fn by_ref(&self) -> &T

§

impl<T> ByRef<T> for T

§

fn by_ref(&self) -> &T

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> DistributionExt for T
where T: ?Sized,

§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

§

impl<T> DistributionExt for T
where T: ?Sized,

§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

§

impl<T> DistributionExt for T
where T: ?Sized,

§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

§

impl<T> MaybeSend for T

§

impl<T> MaybeSendSync for T

§

impl<T> MaybeSync for T