struqture/spins/
plus_minus_operator.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::{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/// PlusMinusOperators are combinations of PlusMinusProducts with specific CalculatorComplex coefficients.
30///
31/// This is a representation of sums of pauli products with weightings, in order to build a full hamiltonian.
32///
33/// # Example
34///
35/// ```
36/// use struqture::prelude::*;
37/// use qoqo_calculator::CalculatorComplex;
38/// use struqture::spins::{OperateOnSpins, PlusMinusProduct, PlusMinusOperator};
39///
40/// let mut so = PlusMinusOperator::new();
41///
42/// // Representing the hamiltonian $ 1/2 \sigma_0^{+} \sigma_1^{+} + 1/5 \sigma_0^{z} $
43/// let pp_0x1x = PlusMinusProduct::new().plus(0).plus(1);
44/// let pp_0z = PlusMinusProduct::new().z(0);
45/// so.add_operator_product(pp_0x1x.clone(), CalculatorComplex::from(0.5)).unwrap();
46/// so.add_operator_product(pp_0z.clone(), CalculatorComplex::from(0.2)).unwrap();
47///
48/// // Access what you set:
49/// assert_eq!(so.get(&pp_0x1x), &CalculatorComplex::from(0.5));
50/// assert_eq!(so.get(&pp_0z), &CalculatorComplex::from(0.2));
51/// ```
52///
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54#[serde(try_from = "PlusMinusOperatorSerialize")]
55#[serde(into = "PlusMinusOperatorSerialize")]
56pub struct PlusMinusOperator {
57    // The internal HashMap of PlusMinusProducts and coefficients (CalculatorComplex)
58    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    // From trait
121    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    // From trait
129    fn iter(&'a self) -> impl ExactSizeIterator<Item = (&'a Self::Index, &'a Self::Value)> {
130        self.internal_map.iter()
131    }
132
133    // From trait
134    fn keys(&'a self) -> impl ExactSizeIterator<Item = &'a Self::Index> {
135        self.internal_map.keys()
136    }
137
138    // From trait
139    fn values(&'a self) -> impl ExactSizeIterator<Item = &'a Self::Value> {
140        self.internal_map.values()
141    }
142
143    // From trait
144    fn remove(&mut self, key: &Self::Index) -> Option<Self::Value> {
145        self.internal_map.shift_remove(key)
146    }
147
148    // From trait
149    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    /// Overwrites an existing entry or sets a new entry in the PlusMinusOperator with the given (PlusMinusProduct key, CalculatorComplex value) pair.
157    ///
158    /// # Arguments
159    ///
160    /// * `key` - The PlusMinusProduct key to set in the PlusMinusOperator.
161    /// * `value` - The corresponding CalculatorComplex value to set for the key in the PlusMinusOperator.
162    ///
163    /// # Returns
164    ///
165    /// * `Ok(Some(CalculatorComplex))` - The key existed, this is the value it had before it was set with the value input.
166    /// * `Ok(None)` - The key did not exist, it has been set with its corresponding value.
167    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    // From trait
185    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
197/// Implements the default function (Default trait) of PlusMinusOperator (an empty PlusMinusOperator).
198///
199impl Default for PlusMinusOperator {
200    fn default() -> Self {
201        Self::new()
202    }
203}
204
205/// Functions for the PlusMinusOperator
206///
207impl PlusMinusOperator {
208    /// Creates a new PlusMinusOperator.
209    ///
210    /// # Returns
211    ///
212    /// * `Self` - The new (empty) PlusMinusOperator.
213    pub fn new() -> Self {
214        PlusMinusOperator {
215            internal_map: IndexMap::new(),
216        }
217    }
218
219    /// Creates a new PlusMinusOperator with pre-allocated capacity.
220    ///
221    /// # Arguments
222    ///
223    /// * `capacity` - The pre-allocated capacity of the system.
224    ///
225    /// # Returns
226    ///
227    /// * `Self` - The new (empty) PlusMinusOperator.
228    pub fn with_capacity(capacity: usize) -> Self {
229        PlusMinusOperator {
230            internal_map: IndexMap::with_capacity(capacity),
231        }
232    }
233
234    /// Gets the maximum index of the PlusMinusOperator.
235    ///
236    /// # Returns
237    ///
238    /// * `usize` - The number of spins in the PlusMinusOperator.
239    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    /// Export to struqture_1 format.
252    #[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    /// Export to struqture_1 format.
264    #[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    /// Converts a PlusMinusOperator into a PauliOperator.
279    ///
280    /// # Arguments
281    ///
282    /// * `value` - The PlusMinusOperator to convert.
283    ///
284    /// # Returns
285    ///
286    /// * `Self` - The PlusMinusOperator converted into a PauliOperator.
287    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    /// Converts a PauliOperator into a PlusMinusOperator.
303    ///
304    /// # Arguments
305    ///
306    /// * `value` - The PauliOperator to convert.
307    ///
308    /// # Returns
309    ///
310    /// * `Self` - The PauliOperator converted into a PlusMinusOperator.
311    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    /// Converts a PlusMinusOperator into a DecoherenceOperator.
327    ///
328    /// # Arguments
329    ///
330    /// * `value` - The PlusMinusOperator to convert.
331    ///
332    /// # Returns
333    ///
334    /// * `Self` - The PlusMinusOperator converted into a DecoherenceOperator.
335    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    /// Converts a DecoherenceOperator into a PlusMinusOperator.
351    ///
352    /// # Arguments
353    ///
354    /// * `value` - The DecoherenceOperator to convert.
355    ///
356    /// # Returns
357    ///
358    /// * `Self` - The DecoherenceOperator converted into a PlusMinusOperator.
359    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    /// Tries to converts a PlusMinusOperator into a PauliHamiltonian.
377    ///
378    /// # Arguments
379    ///
380    /// * `value` - The PlusMinusOperator to try to convert.
381    ///
382    /// # Returns
383    ///
384    /// * `Ok(Self)` - The PlusMinusOperator converted into a PauliHamiltonian.
385    /// * `Err(StruqtureError::NonHermitianOperator)` - Key is naturally hermitian (on-diagonal term), but its corresponding value is not real.
386    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    /// Converts a PauliHamiltonian into a PlusMinusOperator.
394    ///
395    /// # Arguments
396    ///
397    /// * `value` - The PauliHamiltonian to convert.
398    ///
399    /// # Returns
400    ///
401    /// * `Self` - The PauliHamiltonian converted into a PlusMinusOperator.
402    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
419/// Implements the negative sign function of PlusMinusOperator.
420///
421impl ops::Neg for PlusMinusOperator {
422    type Output = PlusMinusOperator;
423    /// Implement minus sign for PlusMinusOperator.
424    ///
425    /// # Returns
426    ///
427    /// * `Self` - The PlusMinusOperator * -1.
428    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
439/// Implements the plus function of PlusMinusOperator by PlusMinusOperator.
440///
441impl<T, V> ops::Add<T> for PlusMinusOperator
442where
443    T: IntoIterator<Item = (PlusMinusProduct, V)>,
444    V: Into<CalculatorComplex>,
445{
446    type Output = Self;
447    /// Implements `+` (add) for two PlusMinusOperators.
448    ///
449    /// # Arguments
450    ///
451    /// * `other` - The PlusMinusOperator to be added.
452    ///
453    /// # Returns
454    ///
455    /// * `Self` - The two PlusMinusOperators added together.
456    ///
457    /// # Panics
458    ///
459    /// * Internal error in add_operator_product.
460    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
469/// Implements the minus function of PlusMinusOperator by PlusMinusOperator.
470///
471impl<T, V> ops::Sub<T> for PlusMinusOperator
472where
473    T: IntoIterator<Item = (PlusMinusProduct, V)>,
474    V: Into<CalculatorComplex>,
475{
476    type Output = Self;
477    /// Implements `-` (subtract) for two PlusMinusOperators.
478    ///
479    /// # Arguments
480    ///
481    /// * `other` - The PlusMinusOperator to be subtracted.
482    ///
483    /// # Returns
484    ///
485    /// * `Self` - The two PlusMinusOperators subtracted.
486    ///
487    /// # Panics
488    ///
489    /// * Internal error in add_operator_product.
490    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
499/// Implements the multiplication function of PlusMinusOperator by CalculatorComplex/CalculatorFloat.
500///
501impl<T> ops::Mul<T> for PlusMinusOperator
502where
503    T: Into<CalculatorComplex>,
504{
505    type Output = Self;
506    /// Implement `*` for PlusMinusOperator and CalculatorComplex/CalculatorFloat.
507    ///
508    /// # Arguments
509    ///
510    /// * `other` - The CalculatorComplex or CalculatorFloat by which to multiply.
511    ///
512    /// # Returns
513    ///
514    /// * `Self` - The PlusMinusOperator multiplied by the CalculatorComplex/CalculatorFloat.
515    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
527/// Implements the into_iter function (IntoIterator trait) of PlusMinusOperator.
528///
529impl IntoIterator for PlusMinusOperator {
530    type Item = (PlusMinusProduct, CalculatorComplex);
531    type IntoIter = indexmap::map::IntoIter<PlusMinusProduct, CalculatorComplex>;
532
533    /// Returns the PlusMinusOperator in Iterator form.
534    ///
535    /// # Returns
536    ///
537    /// * `Self::IntoIter` - The PlusMinusOperator in Iterator form.
538    fn into_iter(self) -> Self::IntoIter {
539        self.internal_map.into_iter()
540    }
541}
542
543/// Implements the into_iter function (IntoIterator trait) of reference PlusMinusOperator.
544///
545impl<'a> IntoIterator for &'a PlusMinusOperator {
546    type Item = (&'a PlusMinusProduct, &'a CalculatorComplex);
547    type IntoIter = Iter<'a, PlusMinusProduct, CalculatorComplex>;
548
549    /// Returns the reference PlusMinusOperator in Iterator form.
550    ///
551    /// # Returns
552    ///
553    /// * `Self::IntoIter` - The reference PlusMinusOperator in Iterator form.
554    fn into_iter(self) -> Self::IntoIter {
555        self.internal_map.iter()
556    }
557}
558
559/// Implements the from_iter function (FromIterator trait) of PlusMinusOperator.
560///
561impl FromIterator<(PlusMinusProduct, CalculatorComplex)> for PlusMinusOperator {
562    /// Returns the object in PlusMinusOperator form, from an Iterator form of the object.
563    ///
564    /// # Arguments
565    ///
566    /// * `iter` - The iterator containing the information from which to create the PlusMinusOperator.
567    ///
568    /// # Returns
569    ///
570    /// * `Self::IntoIter` - The iterator in PlusMinusOperator form.
571    ///
572    /// # Panics
573    ///
574    /// * Internal error in add_operator_product.
575    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
585/// Implements the extend function (Extend trait) of PlusMinusOperator.
586///
587impl Extend<(PlusMinusProduct, CalculatorComplex)> for PlusMinusOperator {
588    /// Extends the PlusMinusOperator by the specified operations (in Iterator form).
589    ///
590    /// # Arguments
591    ///
592    /// * `iter` - The iterator containing the operations by which to extend the PlusMinusOperator.
593    ///
594    /// # Panics
595    ///
596    /// * Internal error in add_operator_product.
597    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
605/// Implements the format function (Display trait) of PlusMinusOperator.
606///
607impl fmt::Display for PlusMinusOperator {
608    /// Formats the PlusMinusOperator using the given formatter.
609    ///
610    /// # Arguments
611    ///
612    /// * `f` - The formatter to use.
613    ///
614    /// # Returns
615    ///
616    /// * `std::fmt::Result` - The formatted PlusMinusOperator.
617    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    /// Implements JordanWignerSpinToFermion for a PlusMinusOperator.
632    ///
633    /// The convention used is that |0> represents an empty fermionic state (spin-orbital),
634    /// and |1> represents an occupied fermionic state.
635    ///
636    /// # Returns
637    ///
638    /// `FermionOperator` - The fermion operator that results from the transformation.
639    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 the Clone and PartialEq traits of PlusMinusOperator
655    #[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 the Clone and PartialEq traits of PlusMinusOperator
673    #[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        // Test Clone trait
686        assert_eq!(sos.clone(), sos);
687
688        // Test PartialEq trait
689        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 the Debug trait of PlusMinusOperator
714    #[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 PlusMinusOperator Serialization and Deserialization traits (readable)
733    #[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 PlusMinusOperator Serialization and Deserialization traits (compact)
782    #[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}