struqture/bosons/bosonic_open_system.rs
1// Copyright © 2021-2023 HQS Quantum Simulations GmbH. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4// in compliance with the License. You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software distributed under the
9// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
10// express or implied. See the License for the specific language governing permissions and
11// limitations under the License.
12
13use super::{BosonHamiltonian, BosonLindbladNoiseOperator};
14use crate::{OpenSystem, OperateOnDensityMatrix, OperateOnModes, StruqtureError};
15use qoqo_calculator::CalculatorFloat;
16use serde::{Deserialize, Serialize};
17use std::fmt::{self, Write};
18use std::ops;
19
20/// BosonLindbladOpenSystems are representations of open systems of bosons, where a system (BosonHamiltonian) interacts with the environment via noise (BosonLindbladNoiseOperator).
21///
22/// # Example
23///
24/// ```
25/// use struqture::prelude::*;
26/// use qoqo_calculator::CalculatorComplex;
27/// use struqture::bosons::{BosonProduct, HermitianBosonProduct, BosonLindbladOpenSystem};
28///
29/// let mut system = BosonLindbladOpenSystem::new();
30///
31/// let bp_0_1 = BosonProduct::new([0], [1]).unwrap();
32/// let bp_0 = HermitianBosonProduct::new([], [0]).unwrap();
33/// system.noise_mut().set((bp_0_1.clone(), bp_0_1.clone()), CalculatorComplex::from(0.5)).unwrap();
34/// system.system_mut().set(bp_0.clone(), CalculatorComplex::from(0.2)).unwrap();
35///
36/// // Access what you set:
37/// assert_eq!(system.noise().get(&(bp_0_1.clone(), bp_0_1.clone())), &CalculatorComplex::from(0.5));
38/// assert_eq!(system.system().get(&bp_0.clone()), &CalculatorComplex::from(0.2));
39/// ```
40///
41#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
42#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
43#[cfg_attr(feature = "json_schema", schemars(deny_unknown_fields))]
44pub struct BosonLindbladOpenSystem {
45 /// The BosonHamiltonian representing the system terms of the open system
46 system: BosonHamiltonian,
47 /// The BosonLindbladNoiseOperator representing the noise terms of the open system
48 noise: BosonLindbladNoiseOperator,
49}
50
51impl crate::SerializationSupport for BosonLindbladOpenSystem {
52 fn struqture_type() -> crate::StruqtureType {
53 crate::StruqtureType::BosonLindbladOpenSystem
54 }
55}
56
57impl OpenSystem<'_> for BosonLindbladOpenSystem {
58 type System = BosonHamiltonian;
59 type Noise = BosonLindbladNoiseOperator;
60
61 // From trait
62 fn noise(&self) -> &Self::Noise {
63 &self.noise
64 }
65
66 // From trait
67 fn system(&self) -> &Self::System {
68 &self.system
69 }
70
71 // From trait
72 fn noise_mut(&mut self) -> &mut Self::Noise {
73 &mut self.noise
74 }
75
76 // From trait
77 fn system_mut(&mut self) -> &mut Self::System {
78 &mut self.system
79 }
80
81 // From trait
82 fn ungroup(self) -> (Self::System, Self::Noise) {
83 (self.system, self.noise)
84 }
85
86 /// Takes a tuple of a system (BosonHamiltonian) and a noise term (BosonLindbladNoiseOperator) and combines them to be a BosonLindbladOpenSystem.
87 ///
88 /// # Arguments
89 ///
90 /// * `system` - The BosonHamiltonian to have in the BosonLindbladOpenSystem.
91 /// * `noise` - The BosonLindbladNoiseOperator to have in the BosonLindbladOpenSystem.
92 ///
93 /// # Returns
94 ///
95 /// * `Ok(Self)` - The BosonLindbladOpenSystem with input system and noise terms.
96 fn group(system: Self::System, noise: Self::Noise) -> Result<Self, StruqtureError> {
97 Ok(Self { system, noise })
98 }
99
100 // From trait
101 fn empty_clone(&self) -> Self {
102 Self::group(self.system.empty_clone(None), self.noise.empty_clone(None))
103 .expect("Internal error.")
104 }
105}
106
107impl OperateOnModes<'_> for BosonLindbladOpenSystem {
108 /// Gets the maximum current_number_modes of the BosonHamiltonian/BosonLindbladNoiseOperator.
109 ///
110 /// # Returns
111 ///
112 /// * `usize` - The number of bosons in the BosonLindbladOpenSystem.
113 fn current_number_modes(&self) -> usize {
114 self.system
115 .current_number_modes()
116 .max(self.noise.current_number_modes())
117 }
118}
119
120/// Functions for the BosonLindbladOpenSystem
121///
122impl BosonLindbladOpenSystem {
123 /// Creates a new BosonLindbladOpenSystem.
124 ///
125 /// # Returns
126 ///
127 /// * `Self` - The new (empty) BosonLindbladOpenSystem.
128 pub fn new() -> Self {
129 BosonLindbladOpenSystem {
130 system: BosonHamiltonian::new(),
131 noise: BosonLindbladNoiseOperator::new(),
132 }
133 }
134
135 /// Export to struqture_1 format.
136 #[cfg(feature = "struqture_1_export")]
137 pub fn to_struqture_1(
138 &self,
139 ) -> Result<struqture_1::bosons::BosonLindbladOpenSystem, StruqtureError> {
140 let new_system = self.system().to_struqture_1()?;
141 let new_noise = self.noise().to_struqture_1()?;
142
143 struqture_1::OpenSystem::group(new_system, new_noise).map_err(
144 |err| StruqtureError::GenericError { msg:
145 format!("Could not convert struqture 2.x BosonLindbladOpenSystem to 1.x BosonLindbladOpenSystem, group function failed: {err:?}.")
146 }
147 )
148 }
149
150 /// Import from struqture_1 format.
151 #[cfg(feature = "struqture_1_import")]
152 pub fn from_struqture_1(
153 value: &struqture_1::bosons::BosonLindbladOpenSystem,
154 ) -> Result<Self, StruqtureError> {
155 let (system_one, noise_one) = struqture_1::OpenSystem::ungroup(value.clone());
156 let new_system = BosonHamiltonian::from_struqture_1(&system_one)?;
157 let new_noise = BosonLindbladNoiseOperator::from_struqture_1(&noise_one)?;
158 Self::group(new_system, new_noise)
159 }
160}
161
162/// Implements the negative sign function of BosonLindbladOpenSystem.
163///
164impl ops::Neg for BosonLindbladOpenSystem {
165 type Output = Self;
166 /// Implement minus sign for BosonLindbladOpenSystem.
167 ///
168 /// # Returns
169 ///
170 /// * `Self` - The BosonLindbladOpenSystem * -1.
171 fn neg(self) -> Self {
172 let (self_sys, self_noise) = self.ungroup();
173 Self {
174 system: self_sys.neg(),
175 noise: self_noise.neg(),
176 }
177 }
178}
179
180/// Implements the plus function of BosonLindbladOpenSystem by BosonLindbladOpenSystem.
181///
182impl ops::Add<BosonLindbladOpenSystem> for BosonLindbladOpenSystem {
183 type Output = Result<Self, StruqtureError>;
184 /// Implements `+` (add) for two BosonLindbladOpenSystems.
185 ///
186 /// # Arguments
187 ///
188 /// * `other` - The BosonLindbladOpenSystem to be added.
189 ///
190 /// # Returns
191 ///
192 /// * `Ok(Self)` - The two BosonLindbladOpenSystems added together.
193 fn add(self, other: BosonLindbladOpenSystem) -> Self::Output {
194 let (self_sys, self_noise) = self.ungroup();
195 let (other_sys, other_noise) = other.ungroup();
196 Self::group((self_sys + other_sys)?, self_noise + other_noise)
197 }
198}
199
200/// Implements the minus function of BosonLindbladOpenSystem by BosonLindbladOpenSystem.
201///
202impl ops::Sub<BosonLindbladOpenSystem> for BosonLindbladOpenSystem {
203 type Output = Result<Self, StruqtureError>;
204 /// Implements `-` (subtract) for two BosonLindbladOpenSystems.
205 ///
206 /// # Arguments
207 ///
208 /// * `other` - The BosonLindbladOpenSystem to be subtracted.
209 ///
210 /// # Returns
211 ///
212 /// * `Ok(Self)` - The two BosonLindbladOpenSystems added together.
213 fn sub(self, other: BosonLindbladOpenSystem) -> Self::Output {
214 let (self_sys, self_noise) = self.ungroup();
215 let (other_sys, other_noise) = other.ungroup();
216 Self::group((self_sys - other_sys)?, self_noise - other_noise)
217 }
218}
219
220/// Implements the multiplication function of BosonLindbladOpenSystem by CalculatorFloat.
221///
222impl ops::Mul<CalculatorFloat> for BosonLindbladOpenSystem {
223 type Output = Self;
224 /// Implement `*` for BosonLindbladOpenSystem and CalculatorFloat.
225 ///
226 /// # Arguments
227 ///
228 /// * `other` - The CalculatorFloat by which to multiply.
229 ///
230 /// # Returns
231 ///
232 /// * `Self` - The BosonLindbladNoiseOperator multiplied by the CalculatorFloat.
233 fn mul(self, rhs: CalculatorFloat) -> Self::Output {
234 Self {
235 system: self.system * rhs.clone(),
236 noise: self.noise * rhs,
237 }
238 }
239}
240
241/// Implements the format function (Display trait) of BosonLindbladOpenSystem.
242///
243impl fmt::Display for BosonLindbladOpenSystem {
244 /// Formats the BosonLindbladOpenSystem using the given formatter.
245 ///
246 /// # Arguments
247 ///
248 /// * `f` - The formatter to use.
249 ///
250 /// # Returns
251 ///
252 /// * `std::fmt::Result` - The formatted BosonLindbladOpenSystem.
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 let mut output = "BosonLindbladOpenSystem{\n".to_string();
255 output.push_str("System: {\n");
256 for (key, val) in self.system.iter() {
257 writeln!(output, "{key}: {val},")?;
258 }
259 output.push_str("}\n");
260 output.push_str("Noise: {\n");
261 for ((row, column), val) in self.noise.iter() {
262 writeln!(output, "({row}, {column}): {val},")?;
263 }
264 output.push_str("}\n");
265 output.push('}');
266
267 write!(f, "{output}")
268 }
269}