1use super::{DecoherenceOperator, DecoherenceProduct, PauliOperator, PauliProduct};
14use crate::fermions::FermionOperator;
15use crate::mappings::JordanWignerSpinToFermion;
16use crate::spins::{PauliHamiltonian, PlusMinusProduct};
17use crate::{OperateOnDensityMatrix, OperateOnState, StruqtureError, SymmetricIndex};
18use num_complex::Complex64;
19use qoqo_calculator::{CalculatorComplex, CalculatorFloat};
20use serde::{Deserialize, Serialize};
21
22use indexmap::map::{Entry, Iter};
23use indexmap::IndexMap;
24
25use std::fmt::{self, Write};
26use std::iter::{FromIterator, IntoIterator};
27use std::ops;
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54#[serde(try_from = "PlusMinusOperatorSerialize")]
55#[serde(into = "PlusMinusOperatorSerialize")]
56pub struct PlusMinusOperator {
57 internal_map: IndexMap<PlusMinusProduct, CalculatorComplex>,
59}
60
61impl crate::SerializationSupport for PlusMinusOperator {
62 fn struqture_type() -> crate::StruqtureType {
63 crate::StruqtureType::PlusMinusOperator
64 }
65}
66
67#[cfg(feature = "json_schema")]
68impl schemars::JsonSchema for PlusMinusOperator {
69 fn schema_name() -> std::borrow::Cow<'static, str> {
70 "PlusMinusOperator".into()
71 }
72
73 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
74 <PlusMinusOperatorSerialize>::json_schema(generator)
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
79#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
80#[cfg_attr(feature = "json_schema", schemars(deny_unknown_fields))]
81struct PlusMinusOperatorSerialize {
82 items: Vec<(PlusMinusProduct, CalculatorFloat, CalculatorFloat)>,
83 serialisation_meta: crate::StruqtureSerialisationMeta,
84}
85
86impl TryFrom<PlusMinusOperatorSerialize> for PlusMinusOperator {
87 type Error = StruqtureError;
88 fn try_from(value: PlusMinusOperatorSerialize) -> Result<Self, Self::Error> {
89 let target_serialisation_meta =
90 <Self as crate::SerializationSupport>::target_serialisation_meta();
91 crate::check_can_be_deserialised(&target_serialisation_meta, &value.serialisation_meta)?;
92 let new_noise_op: PlusMinusOperator = value
93 .items
94 .into_iter()
95 .map(|(key, real, imag)| (key, CalculatorComplex { re: real, im: imag }))
96 .collect();
97 Ok(new_noise_op)
98 }
99}
100
101impl From<PlusMinusOperator> for PlusMinusOperatorSerialize {
102 fn from(value: PlusMinusOperator) -> Self {
103 let serialisation_meta = crate::SerializationSupport::struqture_serialisation_meta(&value);
104
105 let new_noise_op: Vec<(PlusMinusProduct, CalculatorFloat, CalculatorFloat)> = value
106 .into_iter()
107 .map(|(key, val)| (key, val.re, val.im))
108 .collect();
109 Self {
110 items: new_noise_op,
111 serialisation_meta,
112 }
113 }
114}
115
116impl<'a> OperateOnDensityMatrix<'a> for PlusMinusOperator {
117 type Value = CalculatorComplex;
118 type Index = PlusMinusProduct;
119
120 fn get(&self, key: &Self::Index) -> &Self::Value {
122 match self.internal_map.get(key) {
123 Some(value) => value,
124 None => &CalculatorComplex::ZERO,
125 }
126 }
127
128 fn iter(&'a self) -> impl ExactSizeIterator<Item = (&'a Self::Index, &'a Self::Value)> {
130 self.internal_map.iter()
131 }
132
133 fn keys(&'a self) -> impl ExactSizeIterator<Item = &'a Self::Index> {
135 self.internal_map.keys()
136 }
137
138 fn values(&'a self) -> impl ExactSizeIterator<Item = &'a Self::Value> {
140 self.internal_map.values()
141 }
142
143 fn remove(&mut self, key: &Self::Index) -> Option<Self::Value> {
145 self.internal_map.shift_remove(key)
146 }
147
148 fn empty_clone(&self, capacity: Option<usize>) -> Self {
150 match capacity {
151 Some(cap) => Self::with_capacity(cap),
152 None => Self::new(),
153 }
154 }
155
156 fn set(
168 &mut self,
169 key: Self::Index,
170 value: Self::Value,
171 ) -> Result<Option<Self::Value>, StruqtureError> {
172 if value != CalculatorComplex::ZERO {
173 Ok(self.internal_map.insert(key, value))
174 } else {
175 match self.internal_map.entry(key) {
176 Entry::Occupied(val) => Ok(Some(val.shift_remove())),
177 Entry::Vacant(_) => Ok(None),
178 }
179 }
180 }
181}
182
183impl OperateOnState<'_> for PlusMinusOperator {
184 fn hermitian_conjugate(&self) -> Self {
186 let mut new_operator = Self::with_capacity(self.len());
187 for (pauli_product, value) in self.iter() {
188 let (new_boson_product, prefactor) = pauli_product.hermitian_conjugate();
189 new_operator
190 .add_operator_product(new_boson_product, value.conj() * prefactor)
191 .expect("Internal bug in add_operator_product");
192 }
193 new_operator
194 }
195}
196
197impl Default for PlusMinusOperator {
200 fn default() -> Self {
201 Self::new()
202 }
203}
204
205impl PlusMinusOperator {
208 pub fn new() -> Self {
214 PlusMinusOperator {
215 internal_map: IndexMap::new(),
216 }
217 }
218
219 pub fn with_capacity(capacity: usize) -> Self {
229 PlusMinusOperator {
230 internal_map: IndexMap::with_capacity(capacity),
231 }
232 }
233
234 pub fn current_number_spins(&self) -> usize {
240 let mut max_mode: usize = 0;
241 if !self.internal_map.is_empty() {
242 for key in self.internal_map.keys() {
243 if key.current_number_spins() > max_mode {
244 max_mode = key.current_number_spins()
245 }
246 }
247 }
248 max_mode
249 }
250
251 #[cfg(feature = "struqture_1_export")]
253 pub fn to_struqture_1(&self) -> Result<struqture_1::spins::PlusMinusOperator, StruqtureError> {
254 let mut new_pm_system = struqture_1::spins::PlusMinusOperator::new();
255 for (key, val) in self.iter() {
256 let one_key = key.to_struqture_1()?;
257 let _ =
258 struqture_1::OperateOnDensityMatrix::set(&mut new_pm_system, one_key, val.clone());
259 }
260 Ok(new_pm_system)
261 }
262
263 #[cfg(feature = "struqture_1_import")]
265 pub fn from_struqture_1(
266 value: &struqture_1::spins::PlusMinusOperator,
267 ) -> Result<Self, StruqtureError> {
268 let mut new_operator = Self::new();
269 for (key, val) in struqture_1::OperateOnDensityMatrix::iter(value) {
270 let self_key = PlusMinusProduct::from_struqture_1(key)?;
271 let _ = new_operator.set(self_key, val.clone());
272 }
273 Ok(new_operator)
274 }
275}
276
277impl From<PlusMinusOperator> for PauliOperator {
278 fn from(value: PlusMinusOperator) -> Self {
288 let mut new_operator = PauliOperator::with_capacity(2 * value.len());
289 for (product, val) in value.into_iter() {
290 let transscribed_vector: Vec<(PauliProduct, Complex64)> = product.into();
291 for (transscribed_product, prefactor) in transscribed_vector {
292 new_operator
293 .add_operator_product(transscribed_product, val.clone() * prefactor)
294 .expect("Unexpected error adding operators. Internal struqture error");
295 }
296 }
297 new_operator
298 }
299}
300
301impl From<PauliOperator> for PlusMinusOperator {
302 fn from(value: PauliOperator) -> Self {
312 let mut new_operator = PlusMinusOperator::with_capacity(2 * value.len());
313 for (product, val) in value.into_iter() {
314 let transscribed_vector: Vec<(PlusMinusProduct, Complex64)> = product.into();
315 for (transscribed_product, prefactor) in transscribed_vector {
316 new_operator
317 .add_operator_product(transscribed_product, val.clone() * prefactor)
318 .expect("Unexpected error adding operators. Internal struqture error");
319 }
320 }
321 new_operator
322 }
323}
324
325impl From<PlusMinusOperator> for DecoherenceOperator {
326 fn from(value: PlusMinusOperator) -> Self {
336 let mut new_operator = DecoherenceOperator::with_capacity(2 * value.len());
337 for (product, val) in value.into_iter() {
338 let transscribed_vector: Vec<(DecoherenceProduct, Complex64)> = product.into();
339 for (transscribed_product, prefactor) in transscribed_vector {
340 new_operator
341 .add_operator_product(transscribed_product, val.clone() * prefactor)
342 .expect("Unexpected error adding operators. Internal struqture error");
343 }
344 }
345 new_operator
346 }
347}
348
349impl From<DecoherenceOperator> for PlusMinusOperator {
350 fn from(value: DecoherenceOperator) -> Self {
360 let mut new_operator = PlusMinusOperator::with_capacity(2 * value.len());
361 for (product, val) in value.into_iter() {
362 let transscribed_vector: Vec<(PlusMinusProduct, Complex64)> = product.into();
363 for (transscribed_product, prefactor) in transscribed_vector {
364 new_operator
365 .add_operator_product(transscribed_product, val.clone() * prefactor)
366 .expect("Unexpected error adding operators. Internal struqture error");
367 }
368 }
369 new_operator
370 }
371}
372
373impl TryFrom<PlusMinusOperator> for PauliHamiltonian {
374 type Error = StruqtureError;
375
376 fn try_from(value: PlusMinusOperator) -> Result<Self, Self::Error> {
387 let tmp_operator = PauliOperator::from(value).truncate(1e-16);
388 PauliHamiltonian::try_from(tmp_operator)
389 }
390}
391
392impl From<PauliHamiltonian> for PlusMinusOperator {
393 fn from(value: PauliHamiltonian) -> Self {
403 let mut new_operator = PlusMinusOperator::with_capacity(2 * value.len());
404 for (product, val) in value.into_iter() {
405 let transscribed_vector: Vec<(PlusMinusProduct, Complex64)> = product.into();
406 for (transscribed_product, prefactor) in transscribed_vector {
407 new_operator
408 .add_operator_product(
409 transscribed_product,
410 CalculatorComplex::from(val.clone()) * prefactor,
411 )
412 .expect("Unexpected error adding operators. Internal struqture error");
413 }
414 }
415 new_operator.truncate(1e-16)
416 }
417}
418
419impl ops::Neg for PlusMinusOperator {
422 type Output = PlusMinusOperator;
423 fn neg(self) -> Self {
429 let mut internal = IndexMap::with_capacity(self.len());
430 for (key, val) in self {
431 internal.insert(key.clone(), val.neg());
432 }
433 PlusMinusOperator {
434 internal_map: internal,
435 }
436 }
437}
438
439impl<T, V> ops::Add<T> for PlusMinusOperator
442where
443 T: IntoIterator<Item = (PlusMinusProduct, V)>,
444 V: Into<CalculatorComplex>,
445{
446 type Output = Self;
447 fn add(mut self, other: T) -> Self {
461 for (key, value) in other.into_iter() {
462 self.add_operator_product(key.clone(), Into::<CalculatorComplex>::into(value))
463 .expect("Internal bug in add_operator_product");
464 }
465 self
466 }
467}
468
469impl<T, V> ops::Sub<T> for PlusMinusOperator
472where
473 T: IntoIterator<Item = (PlusMinusProduct, V)>,
474 V: Into<CalculatorComplex>,
475{
476 type Output = Self;
477 fn sub(mut self, other: T) -> Self {
491 for (key, value) in other.into_iter() {
492 self.add_operator_product(key.clone(), Into::<CalculatorComplex>::into(value) * -1.0)
493 .expect("Internal bug in add_operator_product");
494 }
495 self
496 }
497}
498
499impl<T> ops::Mul<T> for PlusMinusOperator
502where
503 T: Into<CalculatorComplex>,
504{
505 type Output = Self;
506 fn mul(self, other: T) -> Self {
516 let other_cc = Into::<CalculatorComplex>::into(other);
517 let mut internal = IndexMap::with_capacity(self.len());
518 for (key, val) in self {
519 internal.insert(key, val * other_cc.clone());
520 }
521 PlusMinusOperator {
522 internal_map: internal,
523 }
524 }
525}
526
527impl IntoIterator for PlusMinusOperator {
530 type Item = (PlusMinusProduct, CalculatorComplex);
531 type IntoIter = indexmap::map::IntoIter<PlusMinusProduct, CalculatorComplex>;
532
533 fn into_iter(self) -> Self::IntoIter {
539 self.internal_map.into_iter()
540 }
541}
542
543impl<'a> IntoIterator for &'a PlusMinusOperator {
546 type Item = (&'a PlusMinusProduct, &'a CalculatorComplex);
547 type IntoIter = Iter<'a, PlusMinusProduct, CalculatorComplex>;
548
549 fn into_iter(self) -> Self::IntoIter {
555 self.internal_map.iter()
556 }
557}
558
559impl FromIterator<(PlusMinusProduct, CalculatorComplex)> for PlusMinusOperator {
562 fn from_iter<I: IntoIterator<Item = (PlusMinusProduct, CalculatorComplex)>>(iter: I) -> Self {
576 let mut so = PlusMinusOperator::new();
577 for (pp, cc) in iter {
578 so.add_operator_product(pp, cc)
579 .expect("Internal bug in add_operator_product");
580 }
581 so
582 }
583}
584
585impl Extend<(PlusMinusProduct, CalculatorComplex)> for PlusMinusOperator {
588 fn extend<I: IntoIterator<Item = (PlusMinusProduct, CalculatorComplex)>>(&mut self, iter: I) {
598 for (pp, cc) in iter {
599 self.add_operator_product(pp, cc)
600 .expect("Internal bug in add_operator_product");
601 }
602 }
603}
604
605impl fmt::Display for PlusMinusOperator {
608 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
618 let mut output = "PlusMinusOperator{\n".to_string();
619 for (key, val) in self.iter() {
620 writeln!(output, "{key}: {val},")?;
621 }
622 output.push('}');
623
624 write!(f, "{output}")
625 }
626}
627
628impl JordanWignerSpinToFermion for PlusMinusOperator {
629 type Output = FermionOperator;
630
631 fn jordan_wigner(&self) -> Self::Output {
640 let mut out = FermionOperator::new();
641 for pmp in self.keys() {
642 out = out + pmp.jordan_wigner() * self.get(pmp);
643 }
644 out
645 }
646}
647
648#[cfg(test)]
649mod test {
650 use super::*;
651 use crate::STRUQTURE_VERSION;
652 use serde_test::{assert_tokens, Configure, Token};
653
654 #[test]
656 fn so_from_sos() {
657 let pp: PlusMinusProduct = PlusMinusProduct::new().z(0);
658 let sos = PlusMinusOperatorSerialize {
659 items: vec![(pp.clone(), 0.5.into(), 0.0.into())],
660 serialisation_meta: crate::StruqtureSerialisationMeta {
661 type_name: "PlusMinusOperator".to_string(),
662 min_version: (2, 0, 0),
663 version: STRUQTURE_VERSION.to_string(),
664 },
665 };
666 let mut so = PlusMinusOperator::new();
667 so.set(pp, CalculatorComplex::from(0.5)).unwrap();
668
669 assert_eq!(PlusMinusOperator::try_from(sos.clone()).unwrap(), so);
670 assert_eq!(PlusMinusOperatorSerialize::from(so), sos);
671 }
672 #[test]
674 fn clone_partial_eq() {
675 let pp: PlusMinusProduct = PlusMinusProduct::new().z(0);
676 let sos = PlusMinusOperatorSerialize {
677 items: vec![(pp, 0.5.into(), 0.0.into())],
678 serialisation_meta: crate::StruqtureSerialisationMeta {
679 type_name: "PlusMinusOperator".to_string(),
680 min_version: (2, 0, 0),
681 version: "2.0.0".to_string(),
682 },
683 };
684
685 assert_eq!(sos.clone(), sos);
687
688 let pp_1: PlusMinusProduct = PlusMinusProduct::new().z(0);
690 let sos_1 = PlusMinusOperatorSerialize {
691 items: vec![(pp_1, 0.5.into(), 0.0.into())],
692 serialisation_meta: crate::StruqtureSerialisationMeta {
693 type_name: "PlusMinusOperator".to_string(),
694 min_version: (2, 0, 0),
695 version: "2.0.0".to_string(),
696 },
697 };
698 let pp_2: PlusMinusProduct = PlusMinusProduct::new().z(2);
699 let sos_2 = PlusMinusOperatorSerialize {
700 items: vec![(pp_2, 0.5.into(), 0.0.into())],
701 serialisation_meta: crate::StruqtureSerialisationMeta {
702 type_name: "PlusMinusOperator".to_string(),
703 min_version: (2, 0, 0),
704 version: "2.0.0".to_string(),
705 },
706 };
707 assert!(sos_1 == sos);
708 assert!(sos == sos_1);
709 assert!(sos_2 != sos);
710 assert!(sos != sos_2);
711 }
712
713 #[test]
715 fn debug() {
716 let pp: PlusMinusProduct = PlusMinusProduct::new().z(0);
717 let sos = PlusMinusOperatorSerialize {
718 items: vec![(pp, 0.5.into(), 0.0.into())],
719 serialisation_meta: crate::StruqtureSerialisationMeta {
720 type_name: "PlusMinusOperator".to_string(),
721 min_version: (2, 0, 0),
722 version: "2.0.0".to_string(),
723 },
724 };
725
726 assert_eq!(
727 format!("{sos:?}"),
728 "PlusMinusOperatorSerialize { items: [(PlusMinusProduct { items: [(0, Z)] }, Float(0.5), Float(0.0))], serialisation_meta: StruqtureSerialisationMeta { type_name: \"PlusMinusOperator\", min_version: (2, 0, 0), version: \"2.0.0\" } }"
729 );
730 }
731
732 #[test]
734 fn serde_readable() {
735 let pp = PlusMinusProduct::new().plus(0);
736 let sos = PlusMinusOperatorSerialize {
737 items: vec![(pp, 0.5.into(), 0.0.into())],
738 serialisation_meta: crate::StruqtureSerialisationMeta {
739 type_name: "PlusMinusOperator".to_string(),
740 min_version: (2, 0, 0),
741 version: "2.0.0".to_string(),
742 },
743 };
744
745 assert_tokens(
746 &sos.readable(),
747 &[
748 Token::Struct {
749 name: "PlusMinusOperatorSerialize",
750 len: 2,
751 },
752 Token::Str("items"),
753 Token::Seq { len: Some(1) },
754 Token::Tuple { len: 3 },
755 Token::Str("0+"),
756 Token::F64(0.5),
757 Token::F64(0.0),
758 Token::TupleEnd,
759 Token::SeqEnd,
760 Token::Str("serialisation_meta"),
761 Token::Struct {
762 name: "StruqtureSerialisationMeta",
763 len: 3,
764 },
765 Token::Str("type_name"),
766 Token::Str("PlusMinusOperator"),
767 Token::Str("min_version"),
768 Token::Tuple { len: 3 },
769 Token::U64(2),
770 Token::U64(0),
771 Token::U64(0),
772 Token::TupleEnd,
773 Token::Str("version"),
774 Token::Str("2.0.0"),
775 Token::StructEnd,
776 Token::StructEnd,
777 ],
778 );
779 }
780
781 #[test]
783 fn serde_compact() {
784 let pp = PlusMinusProduct::new().plus(0);
785 let sos = PlusMinusOperatorSerialize {
786 items: vec![(pp, 0.5.into(), 0.0.into())],
787 serialisation_meta: crate::StruqtureSerialisationMeta {
788 type_name: "PlusMinusOperator".to_string(),
789 min_version: (2, 0, 0),
790 version: "2.0.0".to_string(),
791 },
792 };
793
794 assert_tokens(
795 &sos.compact(),
796 &[
797 Token::Struct {
798 name: "PlusMinusOperatorSerialize",
799 len: 2,
800 },
801 Token::Str("items"),
802 Token::Seq { len: Some(1) },
803 Token::Tuple { len: 3 },
804 Token::Seq { len: Some(1) },
805 Token::Tuple { len: 2 },
806 Token::U64(0),
807 Token::UnitVariant {
808 name: "SinglePlusMinusOperator",
809 variant: "Plus",
810 },
811 Token::TupleEnd,
812 Token::SeqEnd,
813 Token::NewtypeVariant {
814 name: "CalculatorFloat",
815 variant: "Float",
816 },
817 Token::F64(0.5),
818 Token::NewtypeVariant {
819 name: "CalculatorFloat",
820 variant: "Float",
821 },
822 Token::F64(0.0),
823 Token::TupleEnd,
824 Token::SeqEnd,
825 Token::Str("serialisation_meta"),
826 Token::Struct {
827 name: "StruqtureSerialisationMeta",
828 len: 3,
829 },
830 Token::Str("type_name"),
831 Token::Str("PlusMinusOperator"),
832 Token::Str("min_version"),
833 Token::Tuple { len: 3 },
834 Token::U64(2),
835 Token::U64(0),
836 Token::U64(0),
837 Token::TupleEnd,
838 Token::Str("version"),
839 Token::Str("2.0.0"),
840 Token::StructEnd,
841 Token::StructEnd,
842 ],
843 );
844 }
845}