Skip to main content

tensor4all_simplett/mpo/
site_mpo.rs

1//! SiteMPO - Center-canonical form of MPO
2//!
3//! A SiteMPO maintains an orthogonality center that can be moved
4//! through the tensor train for efficient local updates.
5
6use super::error::{MPOError, Result};
7use super::mpo::MPO;
8use super::types::{Tensor4, Tensor4Ops};
9use crate::traits::TTScalar;
10
11/// Center-canonical form of MPO with orthogonality center
12///
13/// The tensors to the left of the center are left-orthogonal (left-isometric),
14/// and the tensors to the right are right-orthogonal (right-isometric).
15#[derive(Debug, Clone)]
16pub struct SiteMPO<T: TTScalar> {
17    /// The underlying MPO tensors
18    tensors: Vec<Tensor4<T>>,
19    /// Current orthogonality center position (0-indexed)
20    center: usize,
21}
22
23impl<T: TTScalar> SiteMPO<T> {
24    /// Create a SiteMPO from an MPO, placing the center at the given position
25    pub fn from_mpo(mpo: MPO<T>, center: usize) -> Result<Self> {
26        if mpo.is_empty() {
27            return Err(MPOError::Empty);
28        }
29        if center >= mpo.len() {
30            return Err(MPOError::InvalidCenter {
31                center,
32                max: mpo.len(),
33            });
34        }
35
36        let tensors = mpo.site_tensors().to_vec();
37        let mut result = Self { tensors, center: 0 };
38
39        // Move center to the desired position
40        result.set_center(center)?;
41
42        Ok(result)
43    }
44
45    /// Create a SiteMPO from tensors without validation
46    #[allow(dead_code)]
47    pub(crate) fn from_tensors_unchecked(tensors: Vec<Tensor4<T>>, center: usize) -> Self {
48        Self { tensors, center }
49    }
50
51    /// Get the current orthogonality center position
52    pub fn center(&self) -> usize {
53        self.center
54    }
55
56    /// Get the number of sites
57    pub fn len(&self) -> usize {
58        self.tensors.len()
59    }
60
61    /// Check if empty
62    pub fn is_empty(&self) -> bool {
63        self.tensors.is_empty()
64    }
65
66    /// Get the site tensor at position i
67    pub fn site_tensor(&self, i: usize) -> &Tensor4<T> {
68        &self.tensors[i]
69    }
70
71    /// Get mutable reference to the site tensor at position i
72    pub fn site_tensor_mut(&mut self, i: usize) -> &mut Tensor4<T> {
73        &mut self.tensors[i]
74    }
75
76    /// Get all site tensors
77    pub fn site_tensors(&self) -> &[Tensor4<T>] {
78        &self.tensors
79    }
80
81    /// Get mutable access to site tensors
82    pub fn site_tensors_mut(&mut self) -> &mut [Tensor4<T>] {
83        &mut self.tensors
84    }
85
86    /// Bond dimensions
87    pub fn link_dims(&self) -> Vec<usize> {
88        if self.len() <= 1 {
89            return Vec::new();
90        }
91        (1..self.len())
92            .map(|i| self.tensors[i].left_dim())
93            .collect()
94    }
95
96    /// Site dimensions
97    pub fn site_dims(&self) -> Vec<(usize, usize)> {
98        self.tensors
99            .iter()
100            .map(|t| (t.site_dim_1(), t.site_dim_2()))
101            .collect()
102    }
103
104    /// Maximum bond dimension
105    pub fn rank(&self) -> usize {
106        let lds = self.link_dims();
107        if lds.is_empty() {
108            1
109        } else {
110            *lds.iter().max().unwrap_or(&1)
111        }
112    }
113
114    /// Move the orthogonality center one position to the left
115    pub fn move_center_left(&mut self) -> Result<()> {
116        if self.center == 0 {
117            return Err(MPOError::InvalidOperation {
118                message: "Cannot move center left from position 0".to_string(),
119            });
120        }
121
122        // TODO: Implement QR decomposition to move center left
123        // For now, just update the center position
124        self.center -= 1;
125        Ok(())
126    }
127
128    /// Move the orthogonality center one position to the right
129    pub fn move_center_right(&mut self) -> Result<()> {
130        if self.center >= self.len() - 1 {
131            return Err(MPOError::InvalidOperation {
132                message: "Cannot move center right from last position".to_string(),
133            });
134        }
135
136        // TODO: Implement QR decomposition to move center right
137        // For now, just update the center position
138        self.center += 1;
139        Ok(())
140    }
141
142    /// Move the orthogonality center to the specified position
143    pub fn set_center(&mut self, target: usize) -> Result<()> {
144        if target >= self.len() {
145            return Err(MPOError::InvalidCenter {
146                center: target,
147                max: self.len(),
148            });
149        }
150
151        while self.center < target {
152            self.move_center_right()?;
153        }
154        while self.center > target {
155            self.move_center_left()?;
156        }
157
158        Ok(())
159    }
160
161    /// Convert to basic MPO
162    pub fn into_mpo(self) -> MPO<T> {
163        MPO::from_tensors_unchecked(self.tensors)
164    }
165}
166
167#[cfg(test)]
168mod tests;