use crate::fermions::{FermionOperator, FermionProduct};
use crate::mappings::JordanWignerSpinToFermion;
use crate::prelude::*;
use crate::{StruqtureError, SymmetricIndex};
use num_complex::Complex64;
use qoqo_calculator::*;
use serde::de::{Deserializer, Error, SeqAccess, Visitor};
use serde::ser::{SerializeSeq, Serializer};
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::str::FromStr;
use tinyvec::{TinyVec, TinyVecIterator};
use super::{DecoherenceProduct, PauliProduct, SingleDecoherenceOperator, SinglePauliOperator};
const INTERNAL_BUG_ADD_OPERATOR_PRODUCT: &str =
"Internal bug in add_operator_product for FermionOperator.";
const INTERNAL_BUG_NEW_FERMION_PRODUCT: &str = "Internal bug in FermionProduct::new";
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum SinglePlusMinusOperator {
Identity,
Plus,
Minus,
Z,
}
impl FromStr for SinglePlusMinusOperator {
type Err = StruqtureError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"I" => Ok(SinglePlusMinusOperator::Identity),
"+" => Ok(SinglePlusMinusOperator::Plus),
"-" => Ok(SinglePlusMinusOperator::Minus),
"Z" => Ok(SinglePlusMinusOperator::Z),
_ => Err(StruqtureError::IncorrectPauliEntry {
pauli: s.to_string(),
}),
}
}
}
impl Default for SinglePlusMinusOperator {
fn default() -> Self {
SinglePlusMinusOperator::Identity
}
}
impl fmt::Display for SinglePlusMinusOperator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SinglePlusMinusOperator::Identity => write!(f, "I"),
SinglePlusMinusOperator::Plus => write!(f, "+"),
SinglePlusMinusOperator::Minus => write!(f, "-"),
SinglePlusMinusOperator::Z => write!(f, "Z"),
}
}
}
impl SinglePlusMinusOperator {
pub fn multiply(
left: SinglePlusMinusOperator,
right: SinglePlusMinusOperator,
) -> Vec<(Self, Complex64)> {
match (left, right) {
(SinglePlusMinusOperator::Identity, x) => vec![(x, Complex64::new(1.0, 0.0))],
(x, SinglePlusMinusOperator::Identity) => vec![(x, Complex64::new(1.0, 0.0))],
(SinglePlusMinusOperator::Plus, SinglePlusMinusOperator::Plus) => {
vec![]
}
(SinglePlusMinusOperator::Plus, SinglePlusMinusOperator::Minus) => {
vec![
(SinglePlusMinusOperator::Z, Complex64::new(0.5, 0.0)),
(SinglePlusMinusOperator::Identity, Complex64::new(0.5, 0.0)),
]
}
(SinglePlusMinusOperator::Plus, SinglePlusMinusOperator::Z) => {
vec![(SinglePlusMinusOperator::Plus, Complex64::new(-1.0, 0.0))]
}
(SinglePlusMinusOperator::Minus, SinglePlusMinusOperator::Plus) => {
vec![
(SinglePlusMinusOperator::Z, Complex64::new(-0.5, 0.0)),
(SinglePlusMinusOperator::Identity, Complex64::new(0.5, 0.0)),
]
}
(SinglePlusMinusOperator::Minus, SinglePlusMinusOperator::Minus) => {
vec![]
}
(SinglePlusMinusOperator::Minus, SinglePlusMinusOperator::Z) => {
vec![(SinglePlusMinusOperator::Minus, Complex64::new(1.0, 0.0))]
}
(SinglePlusMinusOperator::Z, SinglePlusMinusOperator::Plus) => {
vec![(SinglePlusMinusOperator::Plus, Complex64::new(1.0, 0.0))]
}
(SinglePlusMinusOperator::Z, SinglePlusMinusOperator::Minus) => {
vec![(SinglePlusMinusOperator::Minus, Complex64::new(-1.0, 0.0))]
}
(SinglePlusMinusOperator::Z, SinglePlusMinusOperator::Z) => {
vec![(SinglePlusMinusOperator::Identity, Complex64::new(1.0, 0.0))]
}
}
}
}
impl From<SinglePlusMinusOperator> for Vec<(SinglePauliOperator, Complex64)> {
fn from(val: SinglePlusMinusOperator) -> Self {
match val {
SinglePlusMinusOperator::Identity => {
vec![(SinglePauliOperator::Identity, Complex64::new(1.0, 0.0))]
}
SinglePlusMinusOperator::Plus => vec![
(SinglePauliOperator::X, Complex64::new(0.5, 0.0)),
(SinglePauliOperator::Y, Complex64::new(0.0, 0.5)),
],
SinglePlusMinusOperator::Minus => vec![
(SinglePauliOperator::X, Complex64::new(0.5, 0.0)),
(SinglePauliOperator::Y, Complex64::new(0.0, -0.5)),
],
SinglePlusMinusOperator::Z => vec![(SinglePauliOperator::Z, Complex64::new(1.0, 0.0))],
}
}
}
impl From<SinglePauliOperator> for Vec<(SinglePlusMinusOperator, Complex64)> {
fn from(val: SinglePauliOperator) -> Self {
match val {
SinglePauliOperator::Identity => {
vec![(SinglePlusMinusOperator::Identity, Complex64::new(1.0, 0.0))]
}
SinglePauliOperator::X => vec![
(SinglePlusMinusOperator::Plus, Complex64::new(1.0, 0.0)),
(SinglePlusMinusOperator::Minus, Complex64::new(1.0, 0.0)),
],
SinglePauliOperator::Y => vec![
(SinglePlusMinusOperator::Plus, Complex64::new(0.0, -1.0)),
(SinglePlusMinusOperator::Minus, Complex64::new(0.0, 1.0)),
],
SinglePauliOperator::Z => vec![(SinglePlusMinusOperator::Z, Complex64::new(1.0, 0.0))],
}
}
}
impl From<SinglePlusMinusOperator> for Vec<(SingleDecoherenceOperator, Complex64)> {
fn from(val: SinglePlusMinusOperator) -> Self {
match val {
SinglePlusMinusOperator::Identity => vec![(
SingleDecoherenceOperator::Identity,
Complex64::new(1.0, 0.0),
)],
SinglePlusMinusOperator::Plus => vec![
(SingleDecoherenceOperator::X, Complex64::new(0.5, 0.0)),
(SingleDecoherenceOperator::IY, Complex64::new(0.5, 0.0)),
],
SinglePlusMinusOperator::Minus => vec![
(SingleDecoherenceOperator::X, Complex64::new(0.5, 0.0)),
(SingleDecoherenceOperator::IY, Complex64::new(-0.5, 0.0)),
],
SinglePlusMinusOperator::Z => {
vec![(SingleDecoherenceOperator::Z, Complex64::new(1.0, 0.0))]
}
}
}
}
impl From<SingleDecoherenceOperator> for Vec<(SinglePlusMinusOperator, Complex64)> {
fn from(val: SingleDecoherenceOperator) -> Self {
match val {
SingleDecoherenceOperator::Identity => {
vec![(SinglePlusMinusOperator::Identity, Complex64::new(1.0, 0.0))]
}
SingleDecoherenceOperator::X => vec![
(SinglePlusMinusOperator::Plus, Complex64::new(1.0, 0.0)),
(SinglePlusMinusOperator::Minus, Complex64::new(1.0, 0.0)),
],
SingleDecoherenceOperator::IY => vec![
(SinglePlusMinusOperator::Plus, Complex64::new(1.0, 0.0)),
(SinglePlusMinusOperator::Minus, Complex64::new(-1.0, 0.0)),
],
SingleDecoherenceOperator::Z => {
vec![(SinglePlusMinusOperator::Z, Complex64::new(1.0, 0.0))]
}
}
}
}
impl From<PauliProduct> for Vec<(PlusMinusProduct, Complex64)> {
fn from(value: PauliProduct) -> Self {
let mut new_vec: Vec<(PlusMinusProduct, Complex64)> =
vec![(PlusMinusProduct::new(), Complex64::new(1.0, 0.0))];
for (index, single) in value.iter() {
let temp_vec: Vec<(SinglePlusMinusOperator, Complex64)> = (*single).into();
let mut temp_new_vec: Vec<(PlusMinusProduct, Complex64)> = Vec::new();
for (new_op, new_prefactor) in temp_vec {
for (product, prefactor) in new_vec.iter() {
let product = product.clone().set_pauli(*index, new_op);
temp_new_vec.push((product, new_prefactor * prefactor))
}
}
new_vec = temp_new_vec;
}
new_vec
}
}
impl From<DecoherenceProduct> for Vec<(PlusMinusProduct, Complex64)> {
fn from(value: DecoherenceProduct) -> Self {
let mut new_vec: Vec<(PlusMinusProduct, Complex64)> =
vec![(PlusMinusProduct::new(), Complex64::new(1.0, 0.0))];
for (index, single) in value.iter() {
let temp_vec: Vec<(SinglePlusMinusOperator, Complex64)> = (*single).into();
let mut temp_new_vec: Vec<(PlusMinusProduct, Complex64)> = Vec::new();
for (new_op, new_prefactor) in temp_vec {
for (product, prefactor) in new_vec.iter() {
let product = product.clone().set_pauli(*index, new_op);
temp_new_vec.push((product, new_prefactor * prefactor))
}
}
new_vec = temp_new_vec;
}
new_vec
}
}
impl From<PlusMinusProduct> for Vec<(PauliProduct, Complex64)> {
fn from(value: PlusMinusProduct) -> Self {
let mut new_vec: Vec<(PauliProduct, Complex64)> =
vec![(PauliProduct::new(), Complex64::new(1.0, 0.0))];
for (index, single) in value.iter() {
let temp_vec: Vec<(SinglePauliOperator, Complex64)> = (*single).into();
let mut temp_new_vec: Vec<(PauliProduct, Complex64)> = Vec::new();
for (new_op, new_prefactor) in temp_vec {
for (product, prefactor) in new_vec.iter() {
let product = product.clone().set_pauli(*index, new_op);
temp_new_vec.push((product, new_prefactor * prefactor))
}
}
new_vec = temp_new_vec;
}
new_vec
}
}
impl From<PlusMinusProduct> for Vec<(DecoherenceProduct, Complex64)> {
fn from(value: PlusMinusProduct) -> Self {
let mut new_vec: Vec<(DecoherenceProduct, Complex64)> =
vec![(DecoherenceProduct::new(), Complex64::new(1.0, 0.0))];
for (index, single) in value.iter() {
let temp_vec: Vec<(SingleDecoherenceOperator, Complex64)> = (*single).into();
let mut temp_new_vec: Vec<(DecoherenceProduct, Complex64)> = Vec::new();
for (new_op, new_prefactor) in temp_vec {
for (product, prefactor) in new_vec.iter() {
let product = product.clone().set_pauli(*index, new_op);
temp_new_vec.push((product, new_prefactor * prefactor))
}
}
new_vec = temp_new_vec;
}
new_vec
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct PlusMinusProduct {
items: TinyVec<[(usize, SinglePlusMinusOperator); 5]>,
}
#[cfg(feature = "json_schema")]
impl schemars::JsonSchema for PlusMinusProduct {
fn schema_name() -> std::borrow::Cow<'static, str> {
"struqture::spins::PlusMinusProduct".into()
}
fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"type": "string",
"description": "Represents products of Plus Minus Spin Operators (Plus, Minus, Z) by a string of spin numbers followed by pauli operators. E.g. 0+10-13Z14+."
})
}
}
impl crate::SerializationSupport for PlusMinusProduct {
fn struqture_type() -> crate::StruqtureType {
crate::StruqtureType::PlusMinusProduct
}
}
impl Serialize for PlusMinusProduct {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let readable = serializer.is_human_readable();
if readable {
serializer.serialize_str(&self.to_string())
} else {
let mut sequence = serializer.serialize_seq(Some(self.items.len()))?;
for item in self.items.iter() {
sequence.serialize_element(item)?;
}
sequence.end()
}
}
}
impl<'de> Deserialize<'de> for PlusMinusProduct {
fn deserialize<D>(deserializer: D) -> Result<PlusMinusProduct, D::Error>
where
D: Deserializer<'de>,
{
let human_readable = deserializer.is_human_readable();
if human_readable {
struct TemporaryVisitor;
impl<'de> Visitor<'de> for TemporaryVisitor {
type Value = PlusMinusProduct;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("String")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
PlusMinusProduct::from_str(v).map_err(|err| E::custom(format!("{err:?}")))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: Error,
{
PlusMinusProduct::from_str(v).map_err(|err| E::custom(format!("{err:?}")))
}
}
deserializer.deserialize_str(TemporaryVisitor)
} else {
struct PlusMinusProductVisitor;
impl<'de> serde::de::Visitor<'de> for PlusMinusProductVisitor {
type Value = PlusMinusProduct;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Formatter::write_str(formatter, "Identifier of PlusMinusProduct variant")
}
fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: SeqAccess<'de>,
{
let mut pp = PlusMinusProduct::new();
while let Some(item) = access.next_element()? {
let entry: Entry = item;
pp = pp.set_pauli(entry.0 .0, entry.0 .1);
}
Ok(pp)
}
}
#[derive(Deserialize)]
#[serde(transparent)]
struct Entry((usize, SinglePlusMinusOperator));
let pp_visitor = PlusMinusProductVisitor;
deserializer.deserialize_seq(pp_visitor)
}
}
}
impl PlusMinusProduct {
pub fn new() -> Self {
PlusMinusProduct {
items: TinyVec::<[(usize, SinglePlusMinusOperator); 5]>::with_capacity(5),
}
}
pub fn set_pauli(self, index: usize, pauli: SinglePlusMinusOperator) -> Self {
let mut pp = self;
if let Some((vecindex, insertindex, index_in_use)) =
pp.items
.iter()
.enumerate()
.find_map(|(vecindex, (innerindex, _))| {
if innerindex >= &index {
Some((vecindex, *innerindex, innerindex == &index))
} else {
None
}
})
{
if index_in_use {
match pauli {
SinglePlusMinusOperator::Identity => {
let _x = pp.items.remove(vecindex);
}
_ => pp.items[vecindex] = (insertindex, pauli),
}
} else {
match pauli {
SinglePlusMinusOperator::Identity => (),
_ => {
pp.items.insert(vecindex, (index, pauli));
}
}
}
} else {
match pauli {
SinglePlusMinusOperator::Identity => (),
_ => {
pp.items.push((index, pauli));
}
}
}
pp
}
pub fn get(&self, index: &usize) -> Option<&SinglePlusMinusOperator> {
self.items
.iter()
.find_map(|(key, value)| if key == index { Some(value) } else { None })
}
pub fn iter(&self) -> std::slice::Iter<'_, (usize, SinglePlusMinusOperator)> {
match &self.items {
TinyVec::Heap(x) => x.iter(),
TinyVec::Inline(x) => x.iter(),
}
}
pub fn current_number_spins(&self) -> usize {
if let Some((max, _)) = self.iter().last() {
*max + 1
} else {
0
}
}
pub fn len(&self) -> usize {
self.iter().len()
}
pub fn is_empty(&self) -> bool {
self.iter().len() == 0
}
pub fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> PlusMinusProduct {
let mut mutable_internal: TinyVec<[(usize, SinglePlusMinusOperator); 5]> =
TinyVec::<[(usize, SinglePlusMinusOperator); 5]>::with_capacity(10);
for (key, val) in self.iter() {
mutable_internal.push(match mapping.get(key) {
Some(x) => (*x, *val),
None => (*key, *val),
});
}
mutable_internal.sort_by(|(left_index, _), (right_index, _)| {
left_index
.partial_cmp(right_index)
.expect("Cannot compare two unsigned integers internal error in struqture.spins")
});
PlusMinusProduct {
items: mutable_internal,
}
}
pub fn concatenate(&self, other: PlusMinusProduct) -> Result<PlusMinusProduct, StruqtureError> {
let mut return_list = self.items.clone();
for (key, val) in other.iter() {
if return_list.iter().any(|(index, _)| index == key) {
return Err(StruqtureError::ProductIndexAlreadyOccupied { index: *key });
} else {
return_list.push((*key, *val));
}
}
return_list.sort_by(|(left_index, _), (right_index, _)| {
left_index
.partial_cmp(right_index)
.expect("Cannot compare two unsigned integers internal error in struqture.spins")
});
Ok(PlusMinusProduct { items: return_list })
}
}
impl Ord for PlusMinusProduct {
fn cmp(&self, other: &Self) -> Ordering {
let me: &TinyVec<[(usize, SinglePlusMinusOperator); 5]> = &(self.items);
let them: &TinyVec<[(usize, SinglePlusMinusOperator); 5]> = &(other.items);
match me.len().cmp(&them.len()) {
Ordering::Less => Ordering::Less,
Ordering::Equal => me.cmp(them), Ordering::Greater => Ordering::Greater,
}
}
}
impl PartialOrd for PlusMinusProduct {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PlusMinusProduct {
pub fn plus(self, index: usize) -> Self {
self.set_pauli(index, SinglePlusMinusOperator::Plus)
}
pub fn minus(self, index: usize) -> Self {
self.set_pauli(index, SinglePlusMinusOperator::Minus)
}
pub fn z(self, index: usize) -> Self {
self.set_pauli(index, SinglePlusMinusOperator::Z)
}
pub fn with_capacity(cap: usize) -> Self {
PlusMinusProduct {
items: TinyVec::<[(usize, SinglePlusMinusOperator); 5]>::with_capacity(cap),
}
}
#[cfg(feature = "struqture_1_export")]
pub fn to_struqture_1(&self) -> Result<struqture_1::spins::PlusMinusProduct, StruqtureError> {
let self_string = self.to_string();
let struqture_1_product = struqture_1::spins::PlusMinusProduct::from_str(&self_string)
.map_err(|err| StruqtureError::GenericError {
msg: format!("{err}"),
})?;
Ok(struqture_1_product)
}
#[cfg(feature = "struqture_1_import")]
pub fn from_struqture_1(
value: &struqture_1::spins::PlusMinusProduct,
) -> Result<Self, StruqtureError> {
let value_string = value.to_string();
let pauli_product = Self::from_str(&value_string)?;
Ok(pauli_product)
}
}
impl SymmetricIndex for PlusMinusProduct {
fn hermitian_conjugate(&self) -> (Self, f64) {
let mut new_plus_minus = PlusMinusProduct::with_capacity(self.items.len());
for (index, single) in self.iter() {
match single {
SinglePlusMinusOperator::Identity => (),
SinglePlusMinusOperator::Plus => {
new_plus_minus
.items
.push((*index, SinglePlusMinusOperator::Minus));
}
SinglePlusMinusOperator::Minus => {
new_plus_minus
.items
.push((*index, SinglePlusMinusOperator::Plus));
}
SinglePlusMinusOperator::Z => {
new_plus_minus
.items
.push((*index, SinglePlusMinusOperator::Z));
}
}
}
(new_plus_minus, 1.0)
}
fn is_natural_hermitian(&self) -> bool {
self.iter().all(|(_, single)| match single {
SinglePlusMinusOperator::Identity => true,
SinglePlusMinusOperator::Plus => false,
SinglePlusMinusOperator::Minus => false,
SinglePlusMinusOperator::Z => true,
})
}
}
impl Default for PlusMinusProduct {
fn default() -> Self {
Self::new()
}
}
impl FromStr for PlusMinusProduct {
type Err = StruqtureError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "I" || s.is_empty() {
Ok(Self::new()) } else {
if !s.starts_with(char::is_numeric) {
return Err(StruqtureError::FromStringFailed {
msg: format!("Missing spin index in the following PlusMinusProduct: {s}"),
});
}
let mut internal: TinyVec<[(usize, SinglePlusMinusOperator); 5]> =
TinyVec::<[(usize, SinglePlusMinusOperator); 5]>::with_capacity(10);
let value = s.to_string();
let vec_paulis = value.split(char::is_numeric).filter(|s| !s.is_empty());
let vec_indices = value
.split(|c| char::is_alphabetic(c) || char::is_ascii_punctuation(&c))
.filter(|s| !s.is_empty());
for (index, pauli) in vec_indices.zip(vec_paulis) {
match index.parse() {
Ok(num) => {
let spin: SinglePlusMinusOperator =
SinglePlusMinusOperator::from_str(pauli)?;
match spin {
SinglePlusMinusOperator::Identity => (),
_ => {
internal.push((num, spin));
}
}
}
Err(_) => {
return Err(StruqtureError::FromStringFailed {
msg: format!("Using {index} instead of unsigned integer as spin index"),
})
}
}
}
internal.sort_by(|(left_index, _), (right_index, _)| {
left_index.partial_cmp(right_index).expect(
"Cannot compare two unsigned integers internal error in struqture.spins",
)
});
match internal.windows(2).all(|w| w[0].0 < w[1].0) {
true => Ok(PlusMinusProduct { items: internal }),
false => Err(StruqtureError::FromStringFailed {
msg: "At least one spin index is used more than once.".to_string(),
}),
}
}
}
}
impl fmt::Display for PlusMinusProduct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut string: String = String::new();
if self.items.is_empty() {
string.push('I');
} else {
for (index, pauli) in self.items.iter() {
string.push_str(format!("{index}").as_str());
string.push_str(format!("{pauli}").as_str());
}
}
write!(f, "{string}")
}
}
impl IntoIterator for PlusMinusProduct {
type Item = (usize, SinglePlusMinusOperator);
type IntoIter = TinyVecIterator<[(usize, SinglePlusMinusOperator); 5]>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl FromIterator<(usize, SinglePlusMinusOperator)> for PlusMinusProduct {
fn from_iter<I: IntoIterator<Item = (usize, SinglePlusMinusOperator)>>(iter: I) -> Self {
let mut pp = PlusMinusProduct::new();
for (index, pauli) in iter {
pp = pp.set_pauli(index, pauli);
}
pp
}
}
impl Extend<(usize, SinglePlusMinusOperator)> for PlusMinusProduct {
fn extend<I: IntoIterator<Item = (usize, SinglePlusMinusOperator)>>(&mut self, iter: I) {
let mut pp = self.clone();
for (index, pauli) in iter {
pp = pp.set_pauli(index, pauli);
}
*self = pp;
}
}
#[inline]
fn _jw_string_term(i: &usize) -> FermionOperator {
let mut fermion_id = FermionOperator::new();
fermion_id
.add_operator_product(
FermionProduct::new([], []).expect(INTERNAL_BUG_ADD_OPERATOR_PRODUCT),
1.0.into(),
)
.expect(INTERNAL_BUG_NEW_FERMION_PRODUCT);
let mut jw_string_term = FermionOperator::new();
jw_string_term
.add_operator_product(
FermionProduct::new([*i], [*i]).expect(INTERNAL_BUG_NEW_FERMION_PRODUCT),
CalculatorComplex::new(-2.0, 0.0),
)
.expect(INTERNAL_BUG_ADD_OPERATOR_PRODUCT);
fermion_id + jw_string_term
}
impl JordanWignerSpinToFermion for PlusMinusProduct {
type Output = FermionOperator;
fn jordan_wigner(&self) -> Self::Output {
let mut fermion_operator = FermionOperator::new();
fermion_operator
.add_operator_product(
FermionProduct::new([], []).expect(INTERNAL_BUG_ADD_OPERATOR_PRODUCT),
1.0.into(),
)
.expect(INTERNAL_BUG_NEW_FERMION_PRODUCT);
for (index, op) in self.iter() {
match op {
SinglePlusMinusOperator::Plus => {
for qubit in 0..*index {
fermion_operator = fermion_operator * _jw_string_term(&qubit);
}
let mut last_term = FermionOperator::new();
last_term
.add_operator_product(
FermionProduct::new([], [*index])
.expect(INTERNAL_BUG_NEW_FERMION_PRODUCT),
1.0.into(),
)
.expect(INTERNAL_BUG_ADD_OPERATOR_PRODUCT);
fermion_operator = fermion_operator * last_term;
}
SinglePlusMinusOperator::Minus => {
for qubit in 0..*index {
fermion_operator = fermion_operator * _jw_string_term(&qubit);
}
let mut last_term = FermionOperator::new();
last_term
.add_operator_product(
FermionProduct::new([*index], [])
.expect(INTERNAL_BUG_NEW_FERMION_PRODUCT),
1.0.into(),
)
.expect(INTERNAL_BUG_ADD_OPERATOR_PRODUCT);
fermion_operator = fermion_operator * last_term;
}
SinglePlusMinusOperator::Z => {
fermion_operator = fermion_operator * _jw_string_term(index);
}
_ => {}
}
}
fermion_operator
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::fermions::{FermionOperator, FermionProduct};
use qoqo_calculator::CalculatorComplex;
#[test]
fn test_jw_string_term() {
let mut fermion_id = FermionOperator::new();
fermion_id
.add_operator_product(
FermionProduct::new([], []).expect(INTERNAL_BUG_ADD_OPERATOR_PRODUCT),
1.0.into(),
)
.expect(INTERNAL_BUG_NEW_FERMION_PRODUCT);
let fermion_number = FermionProduct::new([3], [3]).unwrap();
let mut res = FermionOperator::new();
res.add_operator_product(fermion_number, CalculatorComplex::new(-2.0, 0.0))
.unwrap();
res = fermion_id + res;
assert_eq!(_jw_string_term(&3), res);
}
}