use super::{
MixedDecoherenceProduct, MixedIndex, MixedLindbladNoiseOperator, OperateOnMixedSystems,
};
use crate::prelude::*;
use crate::{OperateOnDensityMatrix, StruqtureError};
use qoqo_calculator::CalculatorComplex;
use serde::{Deserialize, Serialize};
use std::iter::{FromIterator, IntoIterator};
use std::{
fmt::{self, Write},
ops,
};
use tinyvec::TinyVec;
#[cfg(feature = "indexed_map_iterators")]
use indexmap::map::{Iter, Keys, Values};
#[cfg(not(feature = "indexed_map_iterators"))]
use std::collections::hash_map::{Iter, Keys, Values};
#[allow(dead_code)]
#[cfg(feature = "json_schema")]
#[derive(schemars::JsonSchema)]
#[serde(remote = "TinyVec<[Option<usize>; 2]>")]
#[serde(transparent)]
pub(crate) struct TinyVecDef(Vec<Option<usize>>);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct MixedLindbladNoiseSystem {
pub(crate) number_spins: TinyVec<[Option<usize>; 2]>,
pub(crate) number_bosons: TinyVec<[Option<usize>; 2]>,
pub(crate) number_fermions: TinyVec<[Option<usize>; 2]>,
pub(crate) operator: MixedLindbladNoiseOperator,
}
#[cfg(feature = "json_schema")]
impl schemars::JsonSchema for MixedLindbladNoiseSystem {
fn schema_name() -> std::borrow::Cow<'static, str> {
"MixedLindbladNoiseSystem".into()
}
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
<SchemaHelperMixedLindbladNoiseSystem>::json_schema(generator)
}
}
#[cfg(feature = "json_schema")]
#[derive(schemars::JsonSchema)]
#[schemars(deny_unknown_fields)]
#[allow(dead_code)]
struct SchemaHelperMixedLindbladNoiseSystem {
#[serde(with = "TinyVecDef")]
number_spins: TinyVec<[Option<usize>; 2]>,
#[serde(with = "TinyVecDef")]
number_bosons: TinyVec<[Option<usize>; 2]>,
#[serde(with = "TinyVecDef")]
number_fermions: TinyVec<[Option<usize>; 2]>,
pub(crate) operator: MixedLindbladNoiseOperator,
}
impl crate::MinSupportedVersion for MixedLindbladNoiseSystem {}
impl<'a> OperateOnDensityMatrix<'a> for MixedLindbladNoiseSystem {
type Value = CalculatorComplex;
type Index = (MixedDecoherenceProduct, MixedDecoherenceProduct);
type IteratorType = Iter<'a, Self::Index, Self::Value>;
type KeyIteratorType = Keys<'a, Self::Index, Self::Value>;
type ValueIteratorType = Values<'a, Self::Index, Self::Value>;
fn get(&self, key: &Self::Index) -> &Self::Value {
self.operator.get(key)
}
fn iter(&'a self) -> Self::IteratorType {
self.operator.iter()
}
fn keys(&'a self) -> Self::KeyIteratorType {
self.operator.keys()
}
fn values(&'a self) -> Self::ValueIteratorType {
self.operator.values()
}
fn remove(&mut self, key: &Self::Index) -> Option<Self::Value> {
self.operator.remove(key)
}
fn empty_clone(&self, capacity: Option<usize>) -> Self {
match capacity {
Some(cap) => Self {
number_spins: self.number_spins.clone(),
number_bosons: self.number_bosons.clone(),
number_fermions: self.number_fermions.clone(),
operator: MixedLindbladNoiseOperator::with_capacity(
self.number_spins.len(),
self.number_bosons.len(),
self.number_fermions.len(),
cap,
),
},
None => Self {
number_spins: self.number_spins.clone(),
number_bosons: self.number_bosons.clone(),
number_fermions: self.number_fermions.clone(),
operator: MixedLindbladNoiseOperator::new(
self.number_spins.len(),
self.number_bosons.len(),
self.number_fermions.len(),
),
},
}
}
fn set(
&mut self,
key: Self::Index,
value: Self::Value,
) -> Result<Option<Self::Value>, StruqtureError> {
if key.0.spins().len() != self.number_spins.len()
|| key.0.bosons().len() != self.number_bosons.len()
|| key.0.fermions().len() != self.number_fermions.len()
{
return Err(StruqtureError::MissmatchedNumberSubsystems {
target_number_spin_subsystems: self.number_spins.len(),
target_number_boson_subsystems: self.number_bosons.len(),
target_number_fermion_subsystems: self.number_fermions.len(),
actual_number_spin_subsystems: key.0.spins().len(),
actual_number_boson_subsystems: key.0.bosons().len(),
actual_number_fermion_subsystems: key.0.fermions().len(),
});
}
if key.1.spins().len() != self.number_spins.len()
|| key.1.bosons().len() != self.number_bosons.len()
|| key.1.fermions().len() != self.number_fermions.len()
{
return Err(StruqtureError::MissmatchedNumberSubsystems {
target_number_spin_subsystems: self.number_spins.len(),
target_number_boson_subsystems: self.number_bosons.len(),
target_number_fermion_subsystems: self.number_fermions.len(),
actual_number_spin_subsystems: key.1.spins().len(),
actual_number_boson_subsystems: key.1.bosons().len(),
actual_number_fermion_subsystems: key.1.fermions().len(),
});
}
for (x, y) in key.0.bosons().zip(self.number_bosons.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.0.fermions().zip(self.number_fermions.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.0.spins().zip(self.number_spins.clone()) {
if let Some(max_number) = y {
if x.current_number_spins() > max_number {
return Err(StruqtureError::MissmatchedNumberSpins);
}
}
}
for (x, y) in key.1.bosons().zip(self.number_bosons.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.1.fermions().zip(self.number_fermions.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.1.spins().zip(self.number_spins.clone()) {
if let Some(max_number) = y {
if x.current_number_spins() > max_number {
return Err(StruqtureError::MissmatchedNumberSpins);
}
}
}
self.operator.set(key, value)
}
fn add_operator_product(
&mut self,
key: Self::Index,
value: Self::Value,
) -> Result<(), StruqtureError> {
if key.0.spins().len() != self.number_spins.len()
|| key.0.bosons().len() != self.number_bosons.len()
|| key.0.fermions().len() != self.number_fermions.len()
{
return Err(StruqtureError::MissmatchedNumberSubsystems {
target_number_spin_subsystems: self.number_spins.len(),
target_number_boson_subsystems: self.number_bosons.len(),
target_number_fermion_subsystems: self.number_fermions.len(),
actual_number_spin_subsystems: key.0.spins().len(),
actual_number_boson_subsystems: key.0.bosons().len(),
actual_number_fermion_subsystems: key.0.fermions().len(),
});
}
if key.1.spins().len() != self.number_spins.len()
|| key.1.bosons().len() != self.number_bosons.len()
|| key.1.fermions().len() != self.number_fermions.len()
{
return Err(StruqtureError::MissmatchedNumberSubsystems {
target_number_spin_subsystems: self.number_spins.len(),
target_number_boson_subsystems: self.number_bosons.len(),
target_number_fermion_subsystems: self.number_fermions.len(),
actual_number_spin_subsystems: key.1.spins().len(),
actual_number_boson_subsystems: key.1.bosons().len(),
actual_number_fermion_subsystems: key.1.fermions().len(),
});
}
for (x, y) in key.0.bosons().zip(self.number_bosons.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.0.fermions().zip(self.number_fermions.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.0.spins().zip(self.number_spins.clone()) {
if let Some(max_number) = y {
if x.current_number_spins() > max_number {
return Err(StruqtureError::MissmatchedNumberSpins);
}
}
}
for (x, y) in key.1.bosons().zip(self.number_bosons.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.1.fermions().zip(self.number_fermions.clone()) {
if let Some(max_number) = y {
if x.current_number_modes() > max_number {
return Err(StruqtureError::MissmatchedNumberModes);
}
}
}
for (x, y) in key.1.spins().zip(self.number_spins.clone()) {
if let Some(max_number) = y {
if x.current_number_spins() > max_number {
return Err(StruqtureError::MissmatchedNumberSpins);
}
}
}
self.operator.add_operator_product(key, value)
}
}
impl OperateOnMixedSystems<'_> for MixedLindbladNoiseSystem {
fn number_spins(&self) -> Vec<usize> {
self.number_spins
.iter()
.zip(self.current_number_spins())
.map(|(target, current)| target.unwrap_or_else(|| current))
.collect()
}
fn current_number_spins(&self) -> Vec<usize> {
let mut number_spins: Vec<usize> = (0..self.number_spins.len()).map(|_| 0).collect();
for (key_left, key_right) in self.keys() {
for (index, s) in key_left.spins().enumerate() {
let maxk = (s.current_number_spins()).max(s.current_number_spins());
if maxk > number_spins[index] {
number_spins[index] = maxk
}
}
for (index, s) in key_right.spins().enumerate() {
let maxk = (s.current_number_spins()).max(s.current_number_spins());
if maxk > number_spins[index] {
number_spins[index] = maxk
}
}
}
number_spins
}
fn number_bosonic_modes(&self) -> Vec<usize> {
self.number_bosons
.iter()
.zip(self.current_number_bosonic_modes())
.map(|(target, current)| target.unwrap_or_else(|| current))
.collect()
}
fn current_number_bosonic_modes(&self) -> Vec<usize> {
let mut number_bosons: Vec<usize> = (0..self.number_bosons.len()).map(|_| 0).collect();
for (key_left, key_right) in self.keys() {
for (index, b) in key_left.bosons().enumerate() {
let maxk = (b.current_number_modes()).max(b.current_number_modes());
if maxk > number_bosons[index] {
number_bosons[index] = maxk
}
}
for (index, b) in key_right.bosons().enumerate() {
let maxk = (b.current_number_modes()).max(b.current_number_modes());
if maxk > number_bosons[index] {
number_bosons[index] = maxk
}
}
}
number_bosons
}
fn number_fermionic_modes(&self) -> Vec<usize> {
self.number_fermions
.iter()
.zip(self.current_number_fermionic_modes())
.map(|(target, current)| target.unwrap_or_else(|| current))
.collect()
}
fn current_number_fermionic_modes(&self) -> Vec<usize> {
let mut number_fermions: Vec<usize> = (0..self.number_fermions.len()).map(|_| 0).collect();
for (key_left, key_right) in self.keys() {
for (index, f) in key_left.fermions().enumerate() {
let maxk = (f.current_number_modes()).max(f.current_number_modes());
if maxk > number_fermions[index] {
number_fermions[index] = maxk
}
}
for (index, f) in key_right.fermions().enumerate() {
let maxk = (f.current_number_modes()).max(f.current_number_modes());
if maxk > number_fermions[index] {
number_fermions[index] = maxk
}
}
}
number_fermions
}
}
impl MixedLindbladNoiseSystem {
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();
let operator = MixedLindbladNoiseOperator::new(
number_spins.len(),
number_bosons.len(),
number_fermions.len(),
);
MixedLindbladNoiseSystem {
number_spins,
number_bosons,
number_fermions,
operator,
}
}
pub fn with_capacity(
number_spins: impl IntoIterator<Item = Option<usize>>,
number_bosons: impl IntoIterator<Item = Option<usize>>,
number_fermions: impl IntoIterator<Item = Option<usize>>,
capacity: 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();
let operator = MixedLindbladNoiseOperator::with_capacity(
number_spins.len(),
number_bosons.len(),
number_fermions.len(),
capacity,
);
MixedLindbladNoiseSystem {
number_spins,
number_bosons,
number_fermions,
operator,
}
}
pub fn operator(&self) -> &MixedLindbladNoiseOperator {
&self.operator
}
pub fn from_operator(
operator: MixedLindbladNoiseOperator,
number_spins: impl IntoIterator<Item = Option<usize>>,
number_bosons: impl IntoIterator<Item = Option<usize>>,
number_fermions: impl IntoIterator<Item = Option<usize>>,
) -> Result<Self, StruqtureError> {
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();
if operator
.current_number_spins()
.iter()
.zip(number_spins.iter())
.all(|(current, target)| match target {
Some(x) => current <= x,
None => true,
})
&& operator
.current_number_bosonic_modes()
.iter()
.zip(number_bosons.iter())
.all(|(current, target)| match target {
Some(x) => current <= x,
None => true,
})
&& operator
.current_number_fermionic_modes()
.iter()
.zip(number_fermions.iter())
.all(|(current, target)| match target {
Some(x) => current <= x,
None => true,
})
{
Ok(MixedLindbladNoiseSystem {
number_spins,
number_bosons,
number_fermions,
operator,
})
} else {
Err(StruqtureError::NumberSpinsExceeded)
}
}
}
impl ops::Neg for MixedLindbladNoiseSystem {
type Output = Self;
fn neg(mut self) -> Self {
self.operator = self.operator.neg();
self
}
}
impl<T, V> ops::Add<T> for MixedLindbladNoiseSystem
where
T: IntoIterator<Item = ((MixedDecoherenceProduct, MixedDecoherenceProduct), V)>,
V: Into<CalculatorComplex>,
{
type Output = Result<Self, StruqtureError>;
fn add(mut self, other: T) -> Self::Output {
for (key, value) in other.into_iter() {
self.add_operator_product(key.clone(), Into::<CalculatorComplex>::into(value))?;
}
Ok(self)
}
}
impl<T, V> ops::Sub<T> for MixedLindbladNoiseSystem
where
T: IntoIterator<Item = ((MixedDecoherenceProduct, MixedDecoherenceProduct), V)>,
V: Into<CalculatorComplex>,
{
type Output = Result<Self, StruqtureError>;
fn sub(mut self, other: T) -> Self::Output {
for (key, value) in other.into_iter() {
self.add_operator_product(key.clone(), Into::<CalculatorComplex>::into(value) * -1.0)?;
}
Ok(self)
}
}
impl<T> ops::Mul<T> for MixedLindbladNoiseSystem
where
T: Into<CalculatorComplex>,
{
type Output = Self;
fn mul(mut self, other: T) -> Self {
let other_cc = Into::<CalculatorComplex>::into(other);
self.operator = self.operator * other_cc;
self
}
}
impl IntoIterator for MixedLindbladNoiseSystem {
type Item = (
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
);
#[cfg(not(feature = "indexed_map_iterators"))]
type IntoIter = std::collections::hash_map::IntoIter<
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
>;
#[cfg(feature = "indexed_map_iterators")]
type IntoIter = indexmap::map::IntoIter<
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
>;
fn into_iter(self) -> Self::IntoIter {
self.operator.into_iter()
}
}
impl<'a> IntoIterator for &'a MixedLindbladNoiseSystem {
type Item = (
&'a (MixedDecoherenceProduct, MixedDecoherenceProduct),
&'a CalculatorComplex,
);
type IntoIter = Iter<'a, (MixedDecoherenceProduct, MixedDecoherenceProduct), CalculatorComplex>;
fn into_iter(self) -> Self::IntoIter {
self.operator.iter()
}
}
impl
FromIterator<(
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
)> for MixedLindbladNoiseSystem
{
fn from_iter<
I: IntoIterator<
Item = (
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
),
>,
>(
iter: I,
) -> Self {
let mut iterator = iter.into_iter();
match iterator.next() {
Some(first_element) => {
let number_spins: Vec<Option<usize>> = (0..first_element.0 .0.spins().len())
.map(|_| None)
.collect();
let number_bosons: Vec<Option<usize>> = (0..first_element.0 .0.bosons().len())
.map(|_| None)
.collect();
let number_fermions: Vec<Option<usize>> = (0..first_element.0 .0.bosons().len())
.map(|_| None)
.collect();
let mut slno =
MixedLindbladNoiseSystem::new(number_spins, number_bosons, number_fermions);
slno.set(first_element.0, first_element.1)
.expect("Internal error in set");
for (pair, cc) in iterator {
slno.add_operator_product(pair, cc)
.expect("Internal error in add_operator_product");
}
slno
}
None => MixedLindbladNoiseSystem::new([], [], []),
}
}
}
impl
Extend<(
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
)> for MixedLindbladNoiseSystem
{
fn extend<
I: IntoIterator<
Item = (
(MixedDecoherenceProduct, MixedDecoherenceProduct),
CalculatorComplex,
),
>,
>(
&mut self,
iter: I,
) {
for (pp, cc) in iter {
self.add_operator_product(pp, cc)
.expect("Internal error in add_operator_product");
}
}
}
impl fmt::Display for MixedLindbladNoiseSystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut output = "MixedLindbladNoiseSystem(\n".to_string();
output.push_str("number_spins: ");
for n in self.number_spins() {
write!(output, "{n}, ")?;
}
output.push('\n');
output.push_str("number_bosons: ");
for n in self.number_bosonic_modes() {
write!(output, "{n}, ")?;
}
output.push('\n');
output.push_str("number_fermions: ");
for n in self.number_fermionic_modes() {
write!(output, "{n}, ")?;
}
output.push_str(")\n{");
for (key, val) in self.iter() {
writeln!(output, "({}, {}): {},", key.0, key.1, val)?;
}
output.push('}');
write!(f, "{output}")
}
}