pub struct TreeTN<T = TensorDynLen, V = NodeIndex>{ /* private fields */ }Expand description
Tree Tensor Network structure (inspired by ITensorNetworks.jl’s TreeTensorNetwork).
Maintains a graph of tensors connected by bonds (edges).
Each node stores a tensor, and edges store Connection objects
that hold the bond index.
The structure uses SiteIndexNetwork to manage:
- Topology: Graph structure (which nodes connect to which)
- Site Space: Physical indices organized by node
§Type Parameters
T: Tensor type implementingTensorLike(default:TensorDynLen)V: Node name type for named nodes (default: NodeIndex for backward compatibility)
§Construction
TreeTN::new(): Create an empty network, then useadd_tensor()andconnect()to build.TreeTN::from_tensors(tensors, node_names): Create from tensors with auto-connection by matching index IDs.
§Examples
Build a 2-node chain manually and verify node count:
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
// Create site and bond indices
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(3);
let s1 = DynIndex::new_dyn(2);
// Build tensors
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()],
vec![1.0_f64, 2.0, 3.0, 4.0, 5.0, 6.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond.clone(), s1.clone()],
vec![1.0_f64, 2.0, 3.0, 4.0, 5.0, 6.0],
).unwrap();
// Use from_tensors (auto-connects nodes sharing the same index ID)
let tn = TreeTN::<_, String>::from_tensors(
vec![t0, t1],
vec!["A".to_string(), "B".to_string()],
).unwrap();
assert_eq!(tn.node_count(), 2);
assert_eq!(tn.edge_count(), 1);Implementations§
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn reindex_site_space_like(&self, template: &Self) -> Result<Self>
pub fn reindex_site_space_like(&self, template: &Self) -> Result<Self>
Reindex this TreeTN’s site space to match a template network.
The topology must match, and each corresponding node must carry the same
number of site indices with the same dimensions. Site indices are paired
node-by-node after sorting by (dim, id) for deterministic matching.
§Arguments
template- Reference TreeTN whose site index IDs should be adopted
§Returns
A new TreeTN with the same tensor data as self, but site index IDs
rewritten to match template.
§Errors
Returns an error if the two networks have different topologies or incompatible site-space dimensions on any node.
§Examples
use tensor4all_core::{DynIndex, TensorDynLen};
use tensor4all_treetn::TreeTN;
let state_a = make_chain(DynIndex::new_dyn(2), DynIndex::new_dyn(2));
let state_b = make_chain(DynIndex::new_dyn(2), DynIndex::new_dyn(2));
let aligned = state_b.reindex_site_space_like(&state_a).unwrap();
assert!(aligned.share_equivalent_site_index_network(&state_a));Sourcepub fn add_aligned(&self, other: &Self) -> Result<Self>
pub fn add_aligned(&self, other: &Self) -> Result<Self>
Add two TreeTNs after aligning the second operand’s site index IDs to the first.
This is useful when two states share the same topology and site dimensions but were constructed with different site index IDs.
§Arguments
other- The other TreeTN to align and add
§Returns
The direct-sum addition result with site IDs matching self.
§Examples
use tensor4all_core::{DynIndex, TensorDynLen};
use tensor4all_treetn::TreeTN;
let state_a = make_chain(DynIndex::new_dyn(2), DynIndex::new_dyn(2));
let state_b = make_chain(DynIndex::new_dyn(2), DynIndex::new_dyn(2));
let sum = state_a.add_aligned(&state_b).unwrap();
assert_eq!(sum.node_count(), 2);
assert!(sum.share_equivalent_site_index_network(&state_a));Sourcepub fn compute_merged_bond_indices(
&self,
other: &Self,
) -> Result<HashMap<(V, V), MergedBondInfo<T::Index>>>where
V: Ord,
pub fn compute_merged_bond_indices(
&self,
other: &Self,
) -> Result<HashMap<(V, V), MergedBondInfo<T::Index>>>where
V: Ord,
Compute merged bond indices for direct-sum addition.
For each edge in the network, compute the merged bond information containing dimensions from both networks and a new merged index.
§Arguments
other- The other TreeTN to compute merged bonds with
§Returns
A HashMap mapping edge keys (node_name_pair in canonical order) to MergedBondInfo.
§Errors
Returns an error if:
- Networks have incompatible topologies
- Bond indices cannot be found
Sourcepub fn add(&self, other: &Self) -> Result<Self>
pub fn add(&self, other: &Self) -> Result<Self>
Add two TreeTNs using direct-sum construction.
This creates a new TreeTN where each tensor is the direct sum of the
corresponding tensors from self and other, with bond dimensions merged.
The two networks must share the same topology and the same site
index IDs. Use add_aligned if site index IDs differ.
§Arguments
other- The other TreeTN to add
§Returns
A new TreeTN representing the sum.
§Errors
Returns an error if the networks have incompatible structures.
§Examples
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
use tensor4all_treetn::TreeTN;
let s = DynIndex::new_dyn(2);
let t = TensorDynLen::from_dense(vec![s.clone()], vec![1.0_f64, 2.0]).unwrap();
let tn = TreeTN::<_, usize>::from_tensors(vec![t], vec![0]).unwrap();
// Adding a single-node network to itself doubles the values
let sum = tn.add(&tn).unwrap();
let dense = sum.to_dense().unwrap();
let expected = TensorDynLen::from_dense(vec![s], vec![2.0, 4.0]).unwrap();
assert!((&dense - &expected).maxabs() < 1e-12);Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn canonicalize(
self,
canonical_region: impl IntoIterator<Item = V>,
options: CanonicalizationOptions,
) -> Result<Self>
pub fn canonicalize( self, canonical_region: impl IntoIterator<Item = V>, options: CanonicalizationOptions, ) -> Result<Self>
Canonicalize the network towards the specified center using options.
This is the recommended unified API for canonicalization. It accepts:
- Center nodes specified by their node names (V)
CanonicalizationOptionsto control the form and force behavior
§Behavior
- If
options.forceis false (default):- Already at target with same form: returns unchanged (no-op)
- Different form: returns an error (use
options.force()to override)
- If
options.forceis true:- Always performs full canonicalization
§Examples
use tensor4all_treetn::{TreeTN, CanonicalizationOptions};
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(3);
let s1 = DynIndex::new_dyn(2);
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()],
vec![1.0_f64, 2.0, 3.0, 4.0, 5.0, 6.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond.clone(), s1.clone()],
vec![1.0_f64, 2.0, 3.0, 4.0, 5.0, 6.0],
).unwrap();
let tn = TreeTN::<_, String>::from_tensors(
vec![t0, t1],
vec!["A".to_string(), "B".to_string()],
).unwrap();
// Canonicalize towards node "A"
let tn = tn.canonicalize(["A".to_string()], CanonicalizationOptions::default()).unwrap();
assert!(tn.is_canonicalized());Sourcepub fn canonicalize_mut(
&mut self,
canonical_region: impl IntoIterator<Item = V>,
options: CanonicalizationOptions,
) -> Result<()>where
Self: Default,
pub fn canonicalize_mut(
&mut self,
canonical_region: impl IntoIterator<Item = V>,
options: CanonicalizationOptions,
) -> Result<()>where
Self: Default,
Canonicalize the network in-place towards the specified center using options.
This is the &mut self version of Self::canonicalize.
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn sim_internal_inds(&self) -> Self
pub fn sim_internal_inds(&self) -> Self
Create a copy with all internal (link/bond) indices replaced by fresh IDs.
External (site/physical) indices remain unchanged. This is useful when contracting two TreeTNs that might have overlapping internal index IDs.
§Returns
A new TreeTN with all bond indices replaced by sim indices (same dimension,
new unique ID).
Sourcepub fn contract_to_tensor(&self) -> Result<T>where
V: Ord,
pub fn contract_to_tensor(&self) -> Result<T>where
V: Ord,
Contract the TreeTN to a single tensor.
This method contracts all tensors in the network into a single tensor containing all physical indices. The contraction is performed using an edge-based order (post-order DFS edges towards root), processing each edge in sequence and using Connection information to identify which indices to contract.
The result has only site (physical) indices; all bond indices are summed out.
See also to_dense, which is an alias for this method.
§Returns
A single tensor representing the full contraction of the network.
§Errors
Returns an error if:
- The network is empty
- The graph is not a valid tree
- Tensor contraction fails
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorIndex, TensorLike};
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(2);
let s1 = DynIndex::new_dyn(2);
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond, s1.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0],
).unwrap();
let tn = TreeTN::<_, usize>::from_tensors(vec![t0, t1], vec![0, 1]).unwrap();
let dense = tn.contract_to_tensor().unwrap();
// Result has only site indices
assert_eq!(dense.num_external_indices(), 2);Sourcepub fn contract_zipup(
&self,
other: &Self,
center: &V,
svd_policy: Option<SvdTruncationPolicy>,
max_rank: Option<usize>,
) -> Result<Self>
pub fn contract_zipup( &self, other: &Self, center: &V, svd_policy: Option<SvdTruncationPolicy>, max_rank: Option<usize>, ) -> Result<Self>
Contract two TreeTNs with the same topology using the zip-up algorithm.
The zip-up algorithm traverses from leaves towards the center, contracting corresponding nodes from both networks and optionally truncating at each step.
§Algorithm
- Replace internal (bond) indices of both networks with fresh IDs to avoid collision
- Traverse from leaves towards center
- At each edge (child → parent):
- Contract the child tensors from both networks (along their shared site indices)
- Factorize, keeping site indices + parent bond on left (canonical form)
- Store left factor as child tensor in result
- Contract right factor into parent tensor
- Contract the final center tensors
§Arguments
other- The other TreeTN to contract with (must have same topology)center- The center node name towards which to contractsvd_policy- Optional SVD truncation policymax_rank- Optional maximum bond dimension
§Returns
The contracted TreeTN result, or an error if topologies don’t match or contraction fails.
Sourcepub fn contract_zipup_with(
&self,
other: &Self,
center: &V,
form: CanonicalForm,
svd_policy: Option<SvdTruncationPolicy>,
max_rank: Option<usize>,
) -> Result<Self>
pub fn contract_zipup_with( &self, other: &Self, center: &V, form: CanonicalForm, svd_policy: Option<SvdTruncationPolicy>, max_rank: Option<usize>, ) -> Result<Self>
Contract two TreeTNs with the same topology using the zip-up algorithm with a specified form.
See contract_zipup for details.
Sourcepub fn contract_zipup_tree_accumulated(
&self,
other: &Self,
center: &V,
form: CanonicalForm,
svd_policy: Option<SvdTruncationPolicy>,
max_rank: Option<usize>,
) -> Result<Self>
pub fn contract_zipup_tree_accumulated( &self, other: &Self, center: &V, form: CanonicalForm, svd_policy: Option<SvdTruncationPolicy>, max_rank: Option<usize>, ) -> Result<Self>
Contract two TreeTNs using zip-up algorithm with accumulated intermediate tensors.
This is an improved version of zip-up contraction that maintains intermediate tensors (environment tensors) as it processes from leaves towards the root, similar to ITensors.jl’s MPO zip-up algorithm.
§Algorithm
- Process leaves: contract
A[leaf] * B[leaf], factorize, store R at parent - Process internal nodes: contract
[R_accumulated..., A[node], B[node]], factorize, store R_new at parent - Process root: contract
[R_list..., A[root], B[root]], store as final result - Set canonical center
§Arguments
other- The other TreeTN to contract with (must have same topology)center- The center node name towards which to contractform- Canonical form (Unitary/LU/CI)svd_policy- Optional SVD truncation policymax_rank- Optional maximum bond dimension
§Returns
The contracted TreeTN result, or an error if topologies don’t match or contraction fails.
Sourcepub fn contract_naive(&self, other: &Self) -> Result<T>
pub fn contract_naive(&self, other: &Self) -> Result<T>
Contract two TreeTNs using naive full contraction.
This is a reference implementation that:
- Replaces internal indices with fresh IDs (sim_internal_inds)
- Converts both TreeTNs to full tensors
- Contracts along common site indices
The result is a single tensor, not a TreeTN. This is useful for:
- Testing correctness of more sophisticated algorithms like
contract_zipup - Computing exact results for small networks
§Arguments
other- The other TreeTN to contract with (must have same topology)
§Returns
A tensor representing the contracted result.
§Note
This method is O(exp(n)) in both time and memory where n is the number of nodes.
Use contract_zipup for efficient contraction of large networks.
Sourcepub fn validate_ortho_consistency(&self) -> Result<()>
pub fn validate_ortho_consistency(&self) -> Result<()>
Validate that canonical_region and edge ortho_towards are consistent.
Rules:
- If
canonical_regionis empty (not canonicalized), all indices must haveortho_towards == None. - If
canonical_regionis non-empty:- It must form a connected subtree
- All edges from outside the center region must have
ortho_towardspointing towards the center - Edges entirely inside the center region may have
ortho_towards == None
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn extract_subtree(&self, node_names: &[V]) -> Result<Self>
pub fn extract_subtree(&self, node_names: &[V]) -> Result<Self>
Extract a sub-tree from this TreeTN.
Creates a new TreeTN containing only the specified nodes and their connecting edges. Tensors are cloned into the new TreeTN.
§Arguments
node_names- The names of nodes to include in the sub-tree
§Returns
A new TreeTN containing the specified sub-tree, or an error if:
- Any specified node doesn’t exist
- The specified nodes don’t form a connected subtree
§Notes
- Bond indices between included nodes are preserved
- Bond indices to excluded nodes become external (site) indices in the sub-tree
- ortho_towards directions are copied for edges within the sub-tree
- canonical_region is intersected with the extracted nodes
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn replace_subtree(
&mut self,
node_names: &[V],
replacement: &Self,
) -> Result<()>
pub fn replace_subtree( &mut self, node_names: &[V], replacement: &Self, ) -> Result<()>
Replace a sub-tree with another TreeTN of the same topology.
This method replaces the tensors and ortho_towards directions for a subset of nodes with those from another TreeTN. The replacement TreeTN must have the same topology (nodes and edges) as the sub-tree being replaced.
§Arguments
node_names- The names of nodes to replacereplacement- The TreeTN to use as replacement
§Returns
Ok(()) if the replacement succeeds, or an error if:
- Any specified node doesn’t exist
- The replacement doesn’t have the same topology as the extracted sub-tree
- Tensor replacement fails
§Notes
- The replacement TreeTN must have the same nodes, edges, and site indices
- Bond dimensions may differ (this is the typical use case for truncation)
- ortho_towards may differ (will be copied from replacement)
- The original TreeTN is modified in-place
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn log_norm(&mut self) -> Result<f64>
pub fn log_norm(&mut self) -> Result<f64>
Compute log(||TreeTN||_F), the log of the Frobenius norm.
Uses canonicalization to avoid numerical overflow: when canonicalized to a single site with Unitary form, the Frobenius norm of the whole network equals the norm of the center tensor.
§Note
This method is mutable because it may need to canonicalize the network
to a single Unitary center. Use log_norm (without canonicalization) if you
already have a properly canonicalized network.
§Returns
The natural logarithm of the Frobenius norm.
§Errors
Returns an error if:
- The network is empty
- Canonicalization fails
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
let s = DynIndex::new_dyn(2);
let t = TensorDynLen::from_dense(vec![s], vec![3.0_f64, 4.0]).unwrap();
let mut tn = TreeTN::<_, usize>::from_tensors(vec![t], vec![0]).unwrap();
// log(||[3, 4]||) = log(5)
let ln = tn.log_norm().unwrap();
assert!((ln - 5.0_f64.ln()).abs() < 1e-10);Sourcepub fn norm(&mut self) -> Result<f64>
pub fn norm(&mut self) -> Result<f64>
Compute the Frobenius norm of the TreeTN.
Uses log_norm internally: norm = exp(log_norm).
§Note
This method is mutable because it may need to canonicalize the network.
§Errors
Returns an error if the network is empty or canonicalization fails.
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
// Single-node TreeTN with tensor [1, 0, 0, 1] (identity 2x2)
let s0 = DynIndex::new_dyn(2);
let s1 = DynIndex::new_dyn(2);
let t = TensorDynLen::from_dense(
vec![s0.clone(), s1.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0],
).unwrap();
let mut tn = TreeTN::<_, String>::from_tensors(
vec![t],
vec!["A".to_string()],
).unwrap();
// Frobenius norm of [[1,0],[0,1]] = sqrt(2)
let n = tn.norm().unwrap();
assert!((n - 2.0_f64.sqrt()).abs() < 1e-10);Sourcepub fn norm_squared(&mut self) -> Result<f64>
pub fn norm_squared(&mut self) -> Result<f64>
Compute the squared Frobenius norm of the TreeTN.
Returns ||self||^2 = norm()^2.
§Note
This method is mutable because it may need to canonicalize the network.
§Errors
Returns an error if the network is empty or canonicalization fails.
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
let s = DynIndex::new_dyn(2);
let t = TensorDynLen::from_dense(vec![s], vec![3.0_f64, 4.0]).unwrap();
let mut tn = TreeTN::<_, usize>::from_tensors(vec![t], vec![0]).unwrap();
// ||[3, 4]||^2 = 9 + 16 = 25
let nsq = tn.norm_squared().unwrap();
assert!((nsq - 25.0).abs() < 1e-10);Sourcepub fn scale(&mut self, scalar: AnyScalar) -> Result<()>
pub fn scale(&mut self, scalar: AnyScalar) -> Result<()>
Scale the tensor network by a complex scalar.
This multiplies a single node tensor, chosen deterministically as the
minimum-named node, so the represented state is scaled once rather than
applying scalar^n across all nodes.
Scaling a non-center tensor generally invalidates any existing canonicalization metadata, so this method clears the cached canonical region and orthogonality directions after updating the tensor.
§Arguments
scalar- Scalar multiplier applied to the represented tensor network
§Returns
Ok(()) after the selected node tensor has been updated in place
§Errors
Returns an error if the TreeTN is empty or the selected node/tensor cannot be found
§Examples
use tensor4all_core::{AnyScalar, DynIndex, TensorDynLen, TensorIndex, TensorLike};
use tensor4all_treetn::TreeTN;
let s = DynIndex::new_dyn(2);
let t = TensorDynLen::from_dense(vec![s], vec![1.0_f64, -2.0]).unwrap();
let mut tn = TreeTN::<_, usize>::from_tensors(vec![t], vec![0]).unwrap();
tn.scale(AnyScalar::new_real(2.0)).unwrap();
let dense = tn.to_dense().unwrap();
let expected = TensorDynLen::from_dense(
dense.external_indices(),
vec![2.0_f64, -4.0],
).unwrap();
assert!((&dense - &expected).maxabs() < 1e-12);Sourcepub fn inner(&self, other: &Self) -> Result<AnyScalar>
pub fn inner(&self, other: &Self) -> Result<AnyScalar>
Compute the inner product of two TreeTNs.
Computes <self | other> = sum over all indices of conj(self) * other.
Both TreeTNs must have the same site indices (same IDs). Link indices may differ between the two TreeTNs.
§Algorithm
- Replace link indices in
otherwith fresh IDs to avoid collision. - At each node, contract
conj(self_tensor) * other_tensorpairwise. - Sweep from leaves to root, contracting the environment.
This is equivalent to contracting the entire network
conj(self) * other into a scalar.
§Errors
Returns an error if the networks have incompatible topologies.
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
let s = DynIndex::new_dyn(2);
let t = TensorDynLen::from_dense(vec![s], vec![3.0_f64, 4.0]).unwrap();
let tn = TreeTN::<_, usize>::from_tensors(vec![t], vec![0]).unwrap();
// <v|v> = 3^2 + 4^2 = 25
let ip = tn.inner(&tn).unwrap();
assert!((ip.real() - 25.0).abs() < 1e-10);Sourcepub fn to_dense(&self) -> Result<T>
pub fn to_dense(&self) -> Result<T>
Convert the TreeTN to a single dense tensor.
This contracts all tensors in the network along their link/bond indices, producing a single tensor with only site (physical) indices.
This is an alias for contract_to_tensor().
§Warning
This operation can be very expensive for large networks, as the result size grows exponentially with the number of sites.
§Errors
Returns an error if the network is empty or contraction fails.
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorIndex, TensorLike};
// Build a 2-node chain
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(2);
let s1 = DynIndex::new_dyn(2);
// Identity matrices
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond.clone(), s1.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0],
).unwrap();
let tn = TreeTN::<_, String>::from_tensors(
vec![t0, t1],
vec!["A".to_string(), "B".to_string()],
).unwrap();
// Contract to a single dense tensor over site indices s0 and s1
let dense = tn.to_dense().unwrap();
// Result is rank-2 (two site indices s0 and s1)
assert_eq!(dense.num_external_indices(), 2);Sourcepub fn all_site_index_ids(
&self,
) -> Result<(Vec<<T::Index as IndexLike>::Id>, Vec<V>)>
pub fn all_site_index_ids( &self, ) -> Result<(Vec<<T::Index as IndexLike>::Id>, Vec<V>)>
Returns all site index IDs and their owning vertex names.
Returns (index_ids, vertex_names) where index_ids[i] belongs to
vertex vertex_names[i]. Order is unspecified but consistent
between the two vectors.
For evaluate(), pass index_ids and arrange
values in the same order.
Sourcepub fn evaluate(
&self,
index_ids: &[<T::Index as IndexLike>::Id],
values: ColMajorArrayRef<'_, usize>,
) -> Result<Vec<AnyScalar>>
pub fn evaluate( &self, index_ids: &[<T::Index as IndexLike>::Id], values: ColMajorArrayRef<'_, usize>, ) -> Result<Vec<AnyScalar>>
Evaluate the TreeTN at multiple multi-indices (batch).
§Arguments
index_ids- Identifies each site index by its ID (fromall_site_index_ids()). Must enumerate every site index exactly once.values- Column-major array of shape[n_indices, n_points].values.get(&[i, p])is the value ofindex_ids[i]at pointp.
§Returns
A Vec<AnyScalar> of length n_points.
§Errors
Returns an error if:
- The network is empty
valuesshape is inconsistent withindex_ids- An index ID is unknown
- Index values are out of bounds
- Contraction fails
Sourcepub fn all_site_indices(&self) -> Result<(Vec<T::Index>, Vec<V>)>
pub fn all_site_indices(&self) -> Result<(Vec<T::Index>, Vec<V>)>
Returns all site indices and their owning vertex names.
Returns (indices, vertex_names) where indices[i] belongs to
vertex vertex_names[i]. Order is unspecified but consistent
between the two vectors.
This is the Index-based counterpart of
all_site_index_ids(), returning
full Index objects instead of raw IDs.
§Errors
Returns an error if a node’s site space cannot be found.
§Examples
use tensor4all_core::{DynIndex, IndexLike, TensorDynLen, TensorLike};
use tensor4all_treetn::TreeTN;
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(3);
let s1 = DynIndex::new_dyn(2);
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()], vec![1.0, 0.0, 0.0, 0.0, 1.0, 0.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond.clone(), s1.clone()], vec![1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
).unwrap();
let tn = TreeTN::<TensorDynLen, usize>::from_tensors(vec![t0, t1], vec![0, 1]).unwrap();
let (indices, vertices) = tn.all_site_indices().unwrap();
assert_eq!(indices.len(), 2);
assert_eq!(vertices.len(), 2);
// The returned indices contain both s0 and s1
let id_set: std::collections::HashSet<_> = indices.iter().map(|i| *i.id()).collect();
assert!(id_set.contains(s0.id()));
assert!(id_set.contains(s1.id()));Sourcepub fn evaluate_at(
&self,
indices: &[T::Index],
values: ColMajorArrayRef<'_, usize>,
) -> Result<Vec<AnyScalar>>
pub fn evaluate_at( &self, indices: &[T::Index], values: ColMajorArrayRef<'_, usize>, ) -> Result<Vec<AnyScalar>>
Evaluate the TreeTN at multiple multi-indices (batch), using
Index objects instead of raw IDs.
This is a convenience wrapper around evaluate()
that accepts &[T::Index] directly, extracting the IDs
internally.
§Arguments
indices- Identifies each site index by itsIndexobject (e.g. fromall_site_indices()). Must enumerate every site index exactly once.values- Column-major array of shape[n_indices, n_points].values.get(&[i, p])is the value ofindices[i]at pointp.
§Returns
A Vec<AnyScalar> of length n_points.
§Errors
Returns an error if the underlying evaluate()
call fails (see its documentation for details).
§Examples
use tensor4all_core::{ColMajorArrayRef, DynIndex, IndexLike, TensorDynLen, TensorLike};
use tensor4all_treetn::TreeTN;
let s0 = DynIndex::new_dyn(3);
let t0 = TensorDynLen::from_dense(vec![s0.clone()], vec![10.0, 20.0, 30.0]).unwrap();
let tn = TreeTN::<TensorDynLen, usize>::from_tensors(vec![t0], vec![0]).unwrap();
let (indices, _vertices) = tn.all_site_indices().unwrap();
// Evaluate at index value 2
let data = [2usize];
let shape = [indices.len(), 1];
let values = ColMajorArrayRef::new(&data, &shape);
let result = tn.evaluate_at(&indices, values).unwrap();
assert!((result[0].real() - 30.0).abs() < 1e-10);Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn restructure_to<TargetV>(
&self,
target: &SiteIndexNetwork<TargetV, T::Index>,
options: &RestructureOptions,
) -> Result<TreeTN<T, TargetV>>
pub fn restructure_to<TargetV>( &self, target: &SiteIndexNetwork<TargetV, T::Index>, options: &RestructureOptions, ) -> Result<TreeTN<T, TargetV>>
Restructure this TreeTN to match a target site-index network.
This is the plan-first public entry point for Issue #423 B2a.
The current staged implementation already handles:
- fuse-only restructures, where each current node maps to exactly one target node;
- split-only restructures, where each target node maps to exactly one current node;
- swap-only restructures, where the current and target topologies are tree-isomorphic and only the site assignments differ;
- conservative path-based swap-then-fuse restructures, where the current nodes already map uniquely to target nodes but their target groups must be rearranged into contiguous path blocks before fusing;
- conservative mixed split-then-fuse restructures, where each current node has at most one cross-node target fragment that must retain the original external bonds.
Unsupported patterns are reported explicitly. In particular, mixed cases that require both split planning and a subsequent move/swap phase may still remain intentionally staged behind placeholder errors while the pure planner is expanded.
Related types:
RestructureOptionsconfigures the split, transport, and optional final truncation phases.SiteIndexNetworkdescribes the desired final topology plus site grouping.TreeTN::split_toandTreeTN::swap_site_indicesremain the lower-level building blocks that the executor will use.
§Arguments
target- Desired final topology and site grouping.options- Phase-specific options for split, transport, and optional final truncation.
§Returns
A new TreeTN with the target node naming and target site-index
network.
§Errors
Returns an error when the target is structurally incompatible with the current network, or when the requested restructure still needs the staged planner paths for mixed split/move/fuse execution.
§Examples
use std::collections::HashSet;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
use tensor4all_treetn::{RestructureOptions, SiteIndexNetwork, TreeTN};
let left = DynIndex::new_dyn(2);
let right = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(1);
let t0 = TensorDynLen::from_dense(vec![left.clone(), bond.clone()], vec![1.0, 0.0])?;
let t1 = TensorDynLen::from_dense(vec![bond, right.clone()], vec![1.0, 0.0])?;
let treetn = TreeTN::<TensorDynLen, String>::from_tensors(
vec![t0, t1],
vec!["A".to_string(), "B".to_string()],
)?;
let mut target: SiteIndexNetwork<String, DynIndex> = SiteIndexNetwork::new();
assert!(target
.add_node("AB".to_string(), HashSet::from([left.clone(), right.clone()]))
.is_ok());
let result = treetn.restructure_to(&target, &RestructureOptions::default())?;
assert_eq!(result.node_count(), 1);
let dense = result.contract_to_tensor()?;
let expected = treetn.contract_to_tensor()?;
assert!((&dense - &expected).maxabs() < 1e-12);Source§impl<V> TreeTN<TensorDynLen, V>
impl<V> TreeTN<TensorDynLen, V>
Sourcepub fn replace_site_index_with_indices(
&self,
old_index: &DynIndex,
new_indices: &[DynIndex],
order: LinearizationOrder,
) -> Result<Self>
pub fn replace_site_index_with_indices( &self, old_index: &DynIndex, new_indices: &[DynIndex], order: LinearizationOrder, ) -> Result<Self>
Replace one site index with multiple site indices using an exact reshape.
This is a TreeTN-level wrapper around [TensorDynLen::unfuse_index].
It updates the owning node tensor and the site-index metadata, without
introducing any approximation.
§Examples
use tensor4all_core::{DynIndex, LinearizationOrder, TensorDynLen};
use tensor4all_treetn::TreeTN;
let fused = DynIndex::new_dyn(4);
let tensor = TensorDynLen::from_dense(vec![fused.clone()], vec![1.0, 2.0, 3.0, 4.0]).unwrap();
let tn = TreeTN::<TensorDynLen, usize>::from_tensors(vec![tensor], vec![0]).unwrap();
let left = DynIndex::new_dyn(2);
let right = DynIndex::new_dyn(2);
let unfused = tn
.replace_site_index_with_indices(
&fused,
&[left.clone(), right.clone()],
LinearizationOrder::ColumnMajor,
)
.unwrap();
let dense = unfused.contract_to_tensor().unwrap();
let expected = TensorDynLen::from_dense(vec![left, right], vec![1.0, 2.0, 3.0, 4.0]).unwrap();
assert!((&dense - &expected).maxabs() < 1.0e-12);Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn fuse_to<TargetV>(
&self,
target: &SiteIndexNetwork<TargetV, T::Index>,
) -> Result<TreeTN<T, TargetV>>
pub fn fuse_to<TargetV>( &self, target: &SiteIndexNetwork<TargetV, T::Index>, ) -> Result<TreeTN<T, TargetV>>
Fuse (merge) adjacent nodes to match the target structure.
This operation contracts adjacent nodes that should be merged according to
the target SiteIndexNetwork. The target structure must be a “coarsening”
of the current structure: each target node should contain the site indices
of one or more adjacent current nodes.
§Algorithm
- Compare current structure with target structure
- Map each current node to its target node (by matching site indices)
- For each group of current nodes mapping to the same target node:
- Contract all nodes in the group into a single node
- Build the new TreeTN with the fused structure
§Arguments
target- The targetSiteIndexNetworkdefining the desired structure
§Returns
A new TreeTN with the fused structure, or an error if:
- The target structure is incompatible with the current structure
- Nodes to be fused are not connected
§Properties
- Bond dimension: Unchanged (pure contraction, no truncation)
- Commutative: Non-overlapping groups can be merged in any order
§Example
Before: x1_1---x2_1---x1_2---x2_2---x1_3---x2_3 (6 nodes)
After: {x1_1,x2_1}---{x1_2,x2_2}---{x1_3,x2_3} (3 nodes)Sourcepub fn split_to<TargetV>(
&self,
target: &SiteIndexNetwork<TargetV, T::Index>,
options: &SplitOptions,
) -> Result<TreeTN<T, TargetV>>
pub fn split_to<TargetV>( &self, target: &SiteIndexNetwork<TargetV, T::Index>, options: &SplitOptions, ) -> Result<TreeTN<T, TargetV>>
Split nodes to match the target structure.
This operation splits nodes that contain site indices belonging to multiple target nodes. The target structure must be a “refinement” of the current structure: each current node’s site indices should map to one or more target nodes.
§Algorithm (Two-Phase Approach)
Phase 1: Exact factorization (no truncation)
- Build mapping: site index ID -> target node name
- For each current node, check if its site indices map to multiple target nodes
- If so, split the node using QR factorization
- Repeat until all nodes match the target structure
Phase 2: Truncation sweep (optional)
If options.final_sweep is true, perform a truncation sweep to optimize
bond dimensions globally.
§Arguments
target- The targetSiteIndexNetworkdefining the desired structureoptions- Options controlling truncation and final sweep
§Returns
A new TreeTN with the split structure, or an error if:
- The target structure is incompatible with the current structure
- Factorization fails
§Properties
- Bond dimension: May increase during split, controlled by truncation
- Exact (Phase 1): Without truncation, represents the same tensor
§Example
Before: {x1_1,x2_1}---{x1_2,x2_2}---{x1_3,x2_3} (3 nodes, fused)
After: x1_1---x2_1---x1_2---x2_2---x1_3---x2_3 (6 nodes, interleaved)Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn truncate(
self,
canonical_region: impl IntoIterator<Item = V>,
options: TruncationOptions,
) -> Result<Self>
pub fn truncate( self, canonical_region: impl IntoIterator<Item = V>, options: TruncationOptions, ) -> Result<Self>
Truncate the network towards the specified center using options.
This is the recommended unified API for truncation. It accepts:
- Center nodes specified by their node names (V)
TruncationOptionsto control the SVD policy and max_rank
§Algorithm
- Canonicalize the network towards the center (required for truncation)
- Generate a two-site sweep plan using Euler tour traversal
- Apply SVD-based truncation at each step, visiting each edge twice
§Examples
use tensor4all_treetn::{TreeTN, TruncationOptions};
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
// Build a 2-node chain
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(3);
let s1 = DynIndex::new_dyn(2);
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0, 0.0, 0.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond.clone(), s1.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0, 0.0, 0.0],
).unwrap();
let tn = TreeTN::<_, String>::from_tensors(
vec![t0, t1],
vec!["A".to_string(), "B".to_string()],
).unwrap();
// Truncate with max rank 2 towards node "A"
let tn = tn.truncate(
["A".to_string()],
TruncationOptions::default().with_max_rank(2),
).unwrap();
// Bond dimension is now at most 2
assert_eq!(tn.node_count(), 2);Sourcepub fn truncate_mut(
&mut self,
canonical_region: impl IntoIterator<Item = V>,
options: TruncationOptions,
) -> Result<()>
pub fn truncate_mut( &mut self, canonical_region: impl IntoIterator<Item = V>, options: TruncationOptions, ) -> Result<()>
Truncate the network in-place towards the specified center using options.
This is the &mut self version of Self::truncate.
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new empty TreeTN.
Use add_tensor() to add tensors and connect() to establish bonds manually.
Sourcepub fn from_tensors(tensors: Vec<T>, node_names: Vec<V>) -> Result<Self>
pub fn from_tensors(tensors: Vec<T>, node_names: Vec<V>) -> Result<Self>
Create a TreeTN from a list of tensors and node names using einsum rule.
This function connects tensors that share common indices (by ID). The algorithm is O(n) where n is the number of tensors:
- Add all tensors as nodes
- Build a map from index ID to (node, index) pairs in a single pass
- Connect nodes that share the same index ID
§Arguments
tensors- Vector of tensors to add to the networknode_names- Vector of node names corresponding to each tensor
§Returns
A new TreeTN with tensors connected by common indices, or an error if:
- The lengths of
tensorsandnode_namesdon’t match - An index ID appears in more than 2 tensors (TreeTN is a tree, so each bond connects exactly 2 nodes)
- Connection fails (e.g., dimension mismatch)
§Errors
Returns an error if validation fails or connection fails.
§Examples
use tensor4all_treetn::TreeTN;
use tensor4all_core::{DynIndex, TensorDynLen, TensorLike};
let s0 = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(3);
let s1 = DynIndex::new_dyn(2);
let t0 = TensorDynLen::from_dense(
vec![s0.clone(), bond.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0, 0.0, 0.0],
).unwrap();
let t1 = TensorDynLen::from_dense(
vec![bond.clone(), s1.clone()],
vec![1.0_f64, 0.0, 0.0, 1.0, 0.0, 0.0],
).unwrap();
let tn = TreeTN::<_, String>::from_tensors(
vec![t0, t1],
vec!["A".to_string(), "B".to_string()],
).unwrap();
assert_eq!(tn.node_count(), 2);
assert_eq!(tn.edge_count(), 1);Sourcepub fn add_tensor(&mut self, node_name: V, tensor: T) -> Result<NodeIndex>
pub fn add_tensor(&mut self, node_name: V, tensor: T) -> Result<NodeIndex>
Add a tensor to the network with a node name.
Returns the NodeIndex for the newly added tensor.
Also updates the site_index_network with the physical indices (all indices initially, as no connections exist yet).
Sourcepub fn add_tensor_auto_name(&mut self, tensor: T) -> NodeIndex
pub fn add_tensor_auto_name(&mut self, tensor: T) -> NodeIndex
Add a tensor to the network using NodeIndex as the node name.
This method only works when V = NodeIndex.
Returns the NodeIndex for the newly added tensor.
Sourcepub fn connect(
&mut self,
node_a: NodeIndex,
index_a: &T::Index,
node_b: NodeIndex,
index_b: &T::Index,
) -> Result<EdgeIndex>
pub fn connect( &mut self, node_a: NodeIndex, index_a: &T::Index, node_b: NodeIndex, index_b: &T::Index, ) -> Result<EdgeIndex>
Connect two tensors via a specified pair of indices.
The indices must have the same ID (Einsum mode).
§Arguments
node_a- First nodeindex_a- Index on first node to use for connectionnode_b- Second nodeindex_b- Index on second node to use for connection
§Returns
The EdgeIndex of the new connection, or an error if validation fails.
Source§impl<T, V> TreeTN<T, V>
impl<T, V> TreeTN<T, V>
Sourcepub fn tensor_mut(&mut self, node: NodeIndex) -> Option<&mut T>
pub fn tensor_mut(&mut self, node: NodeIndex) -> Option<&mut T>
Get a mutable reference to a tensor by NodeIndex.
Sourcepub fn replace_tensor(
&mut self,
node: NodeIndex,
new_tensor: T,
) -> Result<Option<T>>
pub fn replace_tensor( &mut self, node: NodeIndex, new_tensor: T, ) -> Result<Option<T>>
Replace a tensor at the given node with a new tensor.
Validates that the new tensor contains all indices used in connections to this node. Returns an error if any connection index is missing.
Returns the old tensor if the node exists and validation passes.
Sourcepub fn bond_index(&self, edge: EdgeIndex) -> Option<&T::Index>
pub fn bond_index(&self, edge: EdgeIndex) -> Option<&T::Index>
Get the bond index for a given edge.
Sourcepub fn bond_index_mut(&mut self, edge: EdgeIndex) -> Option<&mut T::Index>
pub fn bond_index_mut(&mut self, edge: EdgeIndex) -> Option<&mut T::Index>
Get a mutable reference to the bond index for a given edge.
Sourcepub fn edges_for_node(&self, node: NodeIndex) -> Vec<(EdgeIndex, NodeIndex)>
pub fn edges_for_node(&self, node: NodeIndex) -> Vec<(EdgeIndex, NodeIndex)>
Get all edges connected to a node.
Sourcepub fn replace_edge_bond(
&mut self,
edge: EdgeIndex,
new_bond_index: T::Index,
) -> Result<()>
pub fn replace_edge_bond( &mut self, edge: EdgeIndex, new_bond_index: T::Index, ) -> Result<()>
Replace the bond index for an edge (e.g., after SVD creates a new bond index).
Also updates site_index_network: the old bond index becomes physical again, and the new bond index is removed from physical indices.
Sourcepub fn sim_linkinds(&self) -> Result<Self>where
T::Index: IndexLike,
pub fn sim_linkinds(&self) -> Result<Self>where
T::Index: IndexLike,
Return a copy with all link/bond indices replaced by fresh IDs.
This is analogous to ITensorMPS.jl’s sim(linkinds, M) / sim!(linkinds, M),
and is mainly useful to avoid accidental index-ID collisions when combining
multiple networks.
Notes:
- This keeps dimensions and conjugate states, but changes identities.
- This updates both endpoint tensors and internal bookkeeping.
Sourcepub fn sim_linkinds_mut(&mut self) -> Result<()>where
T::Index: IndexLike,
pub fn sim_linkinds_mut(&mut self) -> Result<()>where
T::Index: IndexLike,
Replace all link/bond indices with fresh IDs in-place.
See Self::sim_linkinds for details.
Sourcepub fn set_ortho_towards(&mut self, index: &T::Index, dir: Option<V>)
pub fn set_ortho_towards(&mut self, index: &T::Index, dir: Option<V>)
Set the orthogonalization direction for an index (bond or site).
The direction is specified as a node name (or None to clear).
§Arguments
index- The index to set ortho direction fordir- The node name that the ortho points towards, or None to clear
Sourcepub fn ortho_towards_for_index(&self, index: &T::Index) -> Option<&V>
pub fn ortho_towards_for_index(&self, index: &T::Index) -> Option<&V>
Get the node name that the orthogonalization points towards for an index.
Returns None if ortho_towards is not set for this index.
Sourcepub fn set_edge_ortho_towards(
&mut self,
edge: EdgeIndex,
dir: Option<V>,
) -> Result<()>
pub fn set_edge_ortho_towards( &mut self, edge: EdgeIndex, dir: Option<V>, ) -> Result<()>
Set the orthogonalization direction for an edge (by EdgeIndex).
This is a convenience method that looks up the bond index and calls set_ortho_towards.
The direction is specified as a node name (or None to clear). The node must be one of the edge’s endpoints.
Sourcepub fn ortho_towards_node(&self, edge: EdgeIndex) -> Option<&V>
pub fn ortho_towards_node(&self, edge: EdgeIndex) -> Option<&V>
Get the node name that the orthogonalization points towards for an edge.
Returns None if ortho_towards is not set for this edge’s bond index.
Sourcepub fn ortho_towards_node_index(&self, edge: EdgeIndex) -> Option<NodeIndex>
pub fn ortho_towards_node_index(&self, edge: EdgeIndex) -> Option<NodeIndex>
Get the NodeIndex that the orthogonalization points towards for an edge.
Returns None if ortho_towards is not set for this edge’s bond index.
Sourcepub fn validate_tree(&self) -> Result<()>
pub fn validate_tree(&self) -> Result<()>
Validate that the graph is a tree (or forest).
Checks:
- The graph is connected (all nodes reachable from the first node)
- For each connected component: edges = nodes - 1 (tree condition)
Sourcepub fn node_count(&self) -> usize
pub fn node_count(&self) -> usize
Get the number of nodes in the network.
Sourcepub fn edge_count(&self) -> usize
pub fn edge_count(&self) -> usize
Get the number of edges in the network.
Sourcepub fn node_index(&self, node_name: &V) -> Option<NodeIndex>
pub fn node_index(&self, node_name: &V) -> Option<NodeIndex>
Get the NodeIndex for a node by name.
Sourcepub fn rename_node(&mut self, old_name: &V, new_name: V) -> Result<()>
pub fn rename_node(&mut self, old_name: &V, new_name: V) -> Result<()>
Rename an existing node while preserving topology, site space, and orthogonality metadata.
Sourcepub fn edge_between(&self, node_a: &V, node_b: &V) -> Option<EdgeIndex>
pub fn edge_between(&self, node_a: &V, node_b: &V) -> Option<EdgeIndex>
Get the EdgeIndex for the edge between two nodes by name.
Returns None if either node doesn’t exist or there’s no edge between them.
Sourcepub fn node_indices(&self) -> Vec<NodeIndex>
pub fn node_indices(&self) -> Vec<NodeIndex>
Get all node indices in the tree tensor network.
Sourcepub fn node_names(&self) -> Vec<V>
pub fn node_names(&self) -> Vec<V>
Get all node names in the tree tensor network.
Sourcepub fn edges_to_canonicalize_by_names(&self, target: &V) -> Option<Vec<(V, V)>>
pub fn edges_to_canonicalize_by_names(&self, target: &V) -> Option<Vec<(V, V)>>
Compute edges to canonicalize from leaves to target, returning node names.
Returns (from, to) pairs in the order they should be processed:
fromis the node being factorizedtois the parent node (towards target)
This is useful for contract_zipup and similar algorithms that work with node names rather than NodeIndex.
§Arguments
target- Target node name for the orthogonality center
§Returns
None if target node doesn’t exist, otherwise a vector of (from, to) pairs.
Sourcepub fn canonical_region(&self) -> &HashSet<V>
pub fn canonical_region(&self) -> &HashSet<V>
Get a reference to the orthogonalization region (using node names).
When empty, the network is not canonicalized.
Sourcepub fn is_canonicalized(&self) -> bool
pub fn is_canonicalized(&self) -> bool
Check if the network is canonicalized.
Returns true if canonical_region is non-empty, false otherwise.
Sourcepub fn set_canonical_region(
&mut self,
region: impl IntoIterator<Item = V>,
) -> Result<()>
pub fn set_canonical_region( &mut self, region: impl IntoIterator<Item = V>, ) -> Result<()>
Set the orthogonalization region (using node names).
Validates that all specified nodes exist in the graph.
Sourcepub fn clear_canonical_region(&mut self)
pub fn clear_canonical_region(&mut self)
Clear the orthogonalization region (mark network as not canonicalized).
Also clears the canonical form.
Sourcepub fn canonical_form(&self) -> Option<CanonicalForm>
pub fn canonical_form(&self) -> Option<CanonicalForm>
Get the current canonical form.
Returns None if not canonicalized.
Sourcepub fn add_to_canonical_region(&mut self, node_name: V) -> Result<()>
pub fn add_to_canonical_region(&mut self, node_name: V) -> Result<()>
Add a node to the orthogonalization region.
Validates that the node exists in the graph.
Sourcepub fn remove_from_canonical_region(&mut self, node_name: &V) -> bool
pub fn remove_from_canonical_region(&mut self, node_name: &V) -> bool
Remove a node from the orthogonalization region.
Returns true if the node was in the region, false otherwise.
Sourcepub fn site_index_network(&self) -> &SiteIndexNetwork<V, T::Index>
pub fn site_index_network(&self) -> &SiteIndexNetwork<V, T::Index>
Get a reference to the site index network.
The site index network contains both topology (graph structure) and site space (physical indices).
Sourcepub fn site_index_network_mut(&mut self) -> &mut SiteIndexNetwork<V, T::Index>
pub fn site_index_network_mut(&mut self) -> &mut SiteIndexNetwork<V, T::Index>
Get a mutable reference to the site index network.
Sourcepub fn site_space(&self, node_name: &V) -> Option<&HashSet<T::Index>>
pub fn site_space(&self, node_name: &V) -> Option<&HashSet<T::Index>>
Get a reference to the site space (physical indices) for a node.
Sourcepub fn site_space_mut(
&mut self,
node_name: &V,
) -> Option<&mut HashSet<T::Index>>
pub fn site_space_mut( &mut self, node_name: &V, ) -> Option<&mut HashSet<T::Index>>
Get a mutable reference to the site space (physical indices) for a node.
Check if two TreeTNs share equivalent site index network structure.
Two TreeTNs share equivalent structure if:
- Same topology (nodes and edges)
- Same site space for each node
This is used to verify that two TreeTNs can be added or contracted.
§Arguments
other- The other TreeTN to check against
§Returns
true if the networks share equivalent site index structure, false otherwise.
Sourcepub fn same_topology(&self, other: &Self) -> bool
pub fn same_topology(&self, other: &Self) -> bool
Check if two TreeTNs have the same topology (graph structure).
This only checks that both networks have the same nodes and edges, not that they have the same site indices.
Useful for operations like contract_zipup where we need networks
with the same structure but possibly different site indices.
Sourcepub fn same_appearance(&self, other: &Self) -> bool
pub fn same_appearance(&self, other: &Self) -> bool
Check if two TreeTNs have the same “appearance”.
Two TreeTNs have the same appearance if:
- They have the same topology (same nodes and edges)
- They have the same external indices (physical indices) at each node (compared as sets, so order within a node doesn’t matter)
- They have the same orthogonalization direction (ortho_towards) on each edge
This is a weaker check than share_equivalent_site_index_network:
share_equivalent_site_index_network: checks topology + site space (indices)same_appearance: checks topology + site space + ortho_towards directions
Note: This does NOT compare tensor data, only structural information. Note: Bond index IDs may differ between the two TreeTNs (e.g., after independent canonicalization), so we compare ortho_towards by edge position, not by index ID.
§Arguments
other- The other TreeTN to compare against
§Returns
true if both TreeTNs have the same appearance, false otherwise.
Sourcepub fn swap_site_indices(
&mut self,
target_assignment: &HashMap<<T::Index as IndexLike>::Id, V>,
options: &SwapOptions,
) -> Result<()>
pub fn swap_site_indices( &mut self, target_assignment: &HashMap<<T::Index as IndexLike>::Id, V>, options: &SwapOptions, ) -> Result<()>
Reorder site indices so that each index id ends up at the target node.
Builds a pre-computed schedule from the topology plus current and target
site assignments, canonicalizes the network to the schedule root, then
executes the scheduled transport and swap steps.
Partial assignment is supported: indices not listed in
target_assignment stay on their current side of every visited edge.
§Arguments
target_assignment- Map from site index id to target node name.options- Truncation options for each SVD (default: no truncation, exact).
§Errors
Returns an error if target nodes are missing, an index id is unknown, or sweep fails.
Sourcepub fn swap_site_indices_by_index(
&mut self,
target_assignment: &HashMap<T::Index, V>,
options: &SwapOptions,
) -> Result<()>
pub fn swap_site_indices_by_index( &mut self, target_assignment: &HashMap<T::Index, V>, options: &SwapOptions, ) -> Result<()>
Reorder site indices so that each index ends up at the target node.
Index-based version of swap_site_indices.
Accepts T::Index keys instead of T::Index::Id.
§Examples
use std::collections::HashMap;
use tensor4all_core::{DynIndex, IndexLike, TensorDynLen};
use tensor4all_treetn::{SwapOptions, TreeTN};
let node_name_a = "A".to_string();
let node_name_b = "B".to_string();
let idx_a = DynIndex::new_dyn(2);
let idx_b = DynIndex::new_dyn(2);
let bond = DynIndex::new_dyn(1);
let t0 = TensorDynLen::from_dense(vec![idx_a.clone(), bond.clone()], vec![1.0, 0.0])?;
let t1 = TensorDynLen::from_dense(vec![bond, idx_b.clone()], vec![1.0, 0.0])?;
let mut treetn = TreeTN::<TensorDynLen, String>::from_tensors(
vec![t0, t1],
vec![node_name_a.clone(), node_name_b.clone()],
)?;
let mut target = HashMap::new();
target.insert(idx_a.clone(), node_name_b.clone());
treetn.swap_site_indices_by_index(&target, &SwapOptions::default())?;
assert_eq!(
treetn
.site_index_network()
.find_node_by_index_id(idx_a.id())
.map(|name| name.as_str()),
Some(node_name_b.as_str())
);
assert!(treetn.is_canonicalized());Sourcepub fn verify_internal_consistency(&self) -> Result<()>
pub fn verify_internal_consistency(&self) -> Result<()>
Verify internal data consistency by checking structural invariants and reconstructing the TreeTN.
This function performs two categories of checks:
§Structural invariants (fail-fast checks):
0a. Connectivity: All tensors must form a single connected component 0b. Index sharing: Only edge-connected (adjacent) nodes may share index IDs. Non-adjacent nodes sharing an index ID violates tree structure assumptions.
§Reconstruction consistency:
After structural checks pass, clones all tensors and node names, reconstructs
a new TreeTN using from_tensors, and verifies:
- Topology: Same nodes and edges
- Site space: Same physical indices for each node
- Tensors: Same tensor data at each node
This is useful for debugging and testing to ensure that the internal state of a TreeTN is consistent after complex operations.
§Returns
Ok(()) if the internal data is consistent, or Err with details about the inconsistency.
Trait Implementations§
Source§impl<T, V> Operator<T, V> for TreeTN<T, V>
impl<T, V> Operator<T, V> for TreeTN<T, V>
Source§fn site_indices(&self) -> HashSet<T::Index>
fn site_indices(&self) -> HashSet<T::Index>
Source§fn site_index_network(&self) -> &SiteIndexNetwork<V, T::Index>
fn site_index_network(&self) -> &SiteIndexNetwork<V, T::Index>
Source§fn node_names(&self) -> HashSet<V>
fn node_names(&self) -> HashSet<V>
Source§impl<T, V> TensorIndex for TreeTN<T, V>
impl<T, V> TensorIndex for TreeTN<T, V>
Source§fn external_indices(&self) -> Vec<Self::Index>
fn external_indices(&self) -> Vec<Self::Index>
Return all external (site/physical) indices from all nodes.
This collects all site indices from site_index_network.
Bond indices are NOT included (they are internal to the network).
Source§fn replaceind(
&self,
old_index: &Self::Index,
new_index: &Self::Index,
) -> Result<Self>
fn replaceind( &self, old_index: &Self::Index, new_index: &Self::Index, ) -> Result<Self>
Replace an index in this TreeTN.
Looks up the index location (site or link) and replaces it in:
- The tensor containing it
- The appropriate index network (site_index_network or link_index_network)
Note: replace_tensor automatically updates the site_index_network based on
the new tensor’s indices, so we don’t need to manually call replace_site_index.
Source§fn replaceinds(
&self,
old_indices: &[Self::Index],
new_indices: &[Self::Index],
) -> Result<Self>
fn replaceinds( &self, old_indices: &[Self::Index], new_indices: &[Self::Index], ) -> Result<Self>
Replace multiple indices in this TreeTN.
Source§fn num_external_indices(&self) -> usize
fn num_external_indices(&self) -> usize
§fn replaceinds_pairs(
&self,
pairs: &[(Self::Index, Self::Index)],
) -> Result<Self, Error>
fn replaceinds_pairs( &self, pairs: &[(Self::Index, Self::Index)], ) -> Result<Self, Error>
Auto Trait Implementations§
impl<T, V> Freeze for TreeTN<T, V>
impl<T, V> RefUnwindSafe for TreeTN<T, V>where
<T as TensorIndex>::Index: RefUnwindSafe,
V: RefUnwindSafe,
<<T as TensorIndex>::Index as IndexLike>::Id: RefUnwindSafe,
T: RefUnwindSafe,
impl<T, V> Send for TreeTN<T, V>
impl<T, V> Sync for TreeTN<T, V>
impl<T, V> Unpin for TreeTN<T, V>
impl<T, V> UnsafeUnpin for TreeTN<T, V>
impl<T, V> UnwindSafe for TreeTN<T, V>where
<T as TensorIndex>::Index: UnwindSafe,
V: UnwindSafe,
<<T as TensorIndex>::Index as IndexLike>::Id: UnwindSafe,
T: UnwindSafe,
Blanket Implementations§
§impl<U> As for U
impl<U> As for U
§fn as_<T>(self) -> Twhere
T: CastFrom<U>,
fn as_<T>(self) -> Twhere
T: CastFrom<U>,
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 moreSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> Twhere
Self: Distribution<T>,
§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> Twhere
Self: Distribution<T>,
§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> Twhere
Self: Distribution<T>,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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