use super::{MixedHamiltonianSystem, MixedLindbladNoiseSystem, OperateOnMixedSystems};
use crate::{OpenSystem, OperateOnDensityMatrix, StruqtureError};
use qoqo_calculator::CalculatorFloat;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops;
use tinyvec::TinyVec;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "json_schema", schemars(deny_unknown_fields))]
pub struct MixedLindbladOpenSystem {
system: MixedHamiltonianSystem,
noise: MixedLindbladNoiseSystem,
}
impl crate::MinSupportedVersion for MixedLindbladOpenSystem {}
impl OpenSystem<'_> for MixedLindbladOpenSystem {
type System = MixedHamiltonianSystem;
type Noise = MixedLindbladNoiseSystem;
fn noise(&self) -> &Self::Noise {
&self.noise
}
fn system(&self) -> &Self::System {
&self.system
}
fn noise_mut(&mut self) -> &mut Self::Noise {
&mut self.noise
}
fn system_mut(&mut self) -> &mut Self::System {
&mut self.system
}
fn ungroup(self) -> (Self::System, Self::Noise) {
(self.system, self.noise)
}
fn group(system: Self::System, noise: Self::Noise) -> Result<Self, StruqtureError> {
if system.number_spins.len() != noise.number_spins.len()
|| system.number_bosons.len() != noise.number_bosons.len()
|| system.number_fermions.len() != noise.number_fermions.len()
{
return Err(StruqtureError::MissmatchedNumberSubsystems {
target_number_spin_subsystems: system.number_spins.len(),
target_number_boson_subsystems: system.number_bosons.len(),
target_number_fermion_subsystems: system.number_fermions.len(),
actual_number_spin_subsystems: noise.number_spins.len(),
actual_number_boson_subsystems: noise.number_bosons.len(),
actual_number_fermion_subsystems: noise.number_fermions.len(),
});
}
let mut variable_number_spins = system.number_spins.clone();
let noise_number_spins = noise.number_spins.clone();
let noise_number_current_spins = noise.number_spins();
let system_number_current_spins = system.number_spins();
for (index, (system_spins, noise_spins)) in variable_number_spins
.iter_mut()
.zip(noise_number_spins.iter())
.enumerate()
{
if system_spins != noise_spins {
match (*system_spins, noise_spins) {
(Some(n), None) => {
if n < noise_number_current_spins[index] {
return Err(StruqtureError::MissmatchedNumberSpins);
}
}
(None, Some(n)) => {
if *n >= system_number_current_spins[index] {
*system_spins = Some(*n);
} else {
return Err(StruqtureError::MissmatchedNumberSpins);
}
}
(Some(_), Some(_)) => {
return Err(StruqtureError::MissmatchedNumberSpins);
}
_ => panic!("Unexpected missmatch of number modes"),
}
}
}
let mut system = system;
let mut noise = noise;
system.number_spins.clone_from(&variable_number_spins);
noise.number_spins = variable_number_spins;
let mut variable_number_bosons = system.number_bosons.clone();
let noise_number_bosons = noise.number_bosons.clone();
let noise_number_current_bosons = noise.number_bosonic_modes();
let system_number_current_bosons = system.number_bosonic_modes();
for (index, (system_bosons, noise_bosons)) in variable_number_bosons
.iter_mut()
.zip(noise_number_bosons.iter())
.enumerate()
{
if system_bosons != noise_bosons {
match (*system_bosons, noise_bosons) {
(Some(n), None) => {
if n < noise_number_current_bosons[index] {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
(None, Some(n)) => {
if *n >= system_number_current_bosons[index] {
*system_bosons = Some(*n);
} else {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
(Some(_), Some(_)) => {
return Err(StruqtureError::MissmatchedNumberModes);
}
_ => panic!("Unexpected missmatch of number modes"),
}
}
}
system.number_bosons.clone_from(&variable_number_bosons);
noise.number_bosons = variable_number_bosons;
let mut variable_number_fermions = system.number_fermions.clone();
let noise_number_fermions = noise.number_fermions.clone();
let noise_number_current_fermions = noise.number_bosonic_modes();
let system_number_current_fermions = system.number_bosonic_modes();
for (index, (system_fermions, noise_fermions)) in variable_number_fermions
.iter_mut()
.zip(noise_number_fermions.iter())
.enumerate()
{
if system_fermions != noise_fermions {
match (*system_fermions, noise_fermions) {
(Some(n), None) => {
if n < noise_number_current_fermions[index] {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
(None, Some(n)) => {
if *n >= system_number_current_fermions[index] {
*system_fermions = Some(*n);
} else {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
(Some(_), Some(_)) => {
return Err(StruqtureError::MissmatchedNumberModes);
}
_ => panic!("Unexpected missmatch of number modes"),
}
}
}
system.number_fermions.clone_from(&variable_number_fermions);
noise.number_fermions = variable_number_fermions;
Ok(Self { system, noise })
}
fn empty_clone(&self) -> Self {
Self::group(self.system.empty_clone(None), self.noise.empty_clone(None)).expect(
"Internal error: Number of spins in system and noise unexpectedly does not match.",
)
}
}
impl OperateOnMixedSystems<'_> for MixedLindbladOpenSystem {
fn number_spins(&self) -> Vec<usize> {
self.system
.number_spins()
.iter()
.zip(self.noise.number_spins().iter())
.map(|(s, n)| *(s.max(n)))
.collect()
}
fn current_number_spins(&self) -> Vec<usize> {
self.system
.current_number_spins()
.iter()
.zip(self.noise.current_number_spins().iter())
.map(|(s, n)| *(s.max(n)))
.collect()
}
fn number_bosonic_modes(&self) -> Vec<usize> {
self.system
.number_bosonic_modes()
.iter()
.zip(self.noise.number_bosonic_modes().iter())
.map(|(s, n)| *(s.max(n)))
.collect()
}
fn current_number_bosonic_modes(&self) -> Vec<usize> {
self.system
.current_number_bosonic_modes()
.iter()
.zip(self.noise.current_number_bosonic_modes().iter())
.map(|(s, n)| *(s.max(n)))
.collect()
}
fn number_fermionic_modes(&self) -> Vec<usize> {
self.system
.number_fermionic_modes()
.iter()
.zip(self.noise.number_fermionic_modes().iter())
.map(|(s, n)| *(s.max(n)))
.collect()
}
fn current_number_fermionic_modes(&self) -> Vec<usize> {
self.system
.current_number_fermionic_modes()
.iter()
.zip(self.noise.current_number_fermionic_modes().iter())
.map(|(s, n)| *(s.max(n)))
.collect()
}
}
impl MixedLindbladOpenSystem {
pub fn new(
number_spins: impl IntoIterator<Item = Option<usize>>,
number_bosons: impl IntoIterator<Item = Option<usize>>,
number_fermions: impl IntoIterator<Item = Option<usize>>,
) -> Self {
let number_spins: TinyVec<[Option<usize>; 2]> = number_spins.into_iter().collect();
let number_bosons: TinyVec<[Option<usize>; 2]> = number_bosons.into_iter().collect();
let number_fermions: TinyVec<[Option<usize>; 2]> = number_fermions.into_iter().collect();
MixedLindbladOpenSystem {
system: MixedHamiltonianSystem::new(
number_spins.clone(),
number_bosons.clone(),
number_fermions.clone(),
),
noise: MixedLindbladNoiseSystem::new(number_spins, number_bosons, number_fermions),
}
}
}
impl ops::Neg for MixedLindbladOpenSystem {
type Output = Self;
fn neg(self) -> Self {
let (self_sys, self_noise) = self.ungroup();
Self {
system: self_sys.neg(),
noise: self_noise.neg(),
}
}
}
impl ops::Add<MixedLindbladOpenSystem> for MixedLindbladOpenSystem {
type Output = Result<Self, StruqtureError>;
fn add(self, other: MixedLindbladOpenSystem) -> Self::Output {
let (self_sys, self_noise) = self.ungroup();
let (other_sys, other_noise) = other.ungroup();
Self::group((self_sys + other_sys)?, (self_noise + other_noise)?)
}
}
impl ops::Sub<MixedLindbladOpenSystem> for MixedLindbladOpenSystem {
type Output = Result<Self, StruqtureError>;
fn sub(self, other: MixedLindbladOpenSystem) -> Self::Output {
let (self_sys, self_noise) = self.ungroup();
let (other_sys, other_noise) = other.ungroup();
Self::group((self_sys - other_sys)?, (self_noise - other_noise)?)
}
}
impl ops::Mul<CalculatorFloat> for MixedLindbladOpenSystem {
type Output = Self;
fn mul(self, rhs: CalculatorFloat) -> Self::Output {
Self {
system: self.system * rhs.clone(),
noise: self.noise * rhs,
}
}
}
impl fmt::Display for MixedLindbladOpenSystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut output = "MixedLindbladOpenSystem{\n".to_string();
output.push_str("System: {\n");
output.push_str(format!("{}", self.system()).as_str());
output.push_str("}\n");
output.push_str("Noise: {\n");
output.push_str(format!("{}", self.noise()).as_str());
output.push_str("}\n");
output.push('}');
write!(f, "{output}")
}
}