microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
source/paulimer/src/pauli/operators.rs
222lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | // fn is_sorted<Items: Iterator<Item = usize>>(items: Items) -> bool { |
| 5 | // let vec_items: Vec<usize> = items.collect(); |
| 6 | // equal(sorted(vec_items.iter()), vec_items.iter()) |
| 7 | // } |
| 8 | |
| 9 | // MulAssign for PauliUnitary and PauliUnitaryAbs with rhs that implements Pauli or PauliAbs |
| 10 | |
| 11 | use std::ops::{Mul, MulAssign, Neg}; |
| 12 | |
| 13 | use crate::NeutralElement; |
| 14 | |
| 15 | use super::{ |
| 16 | generic::{PhaseExponent, PhaseExponentMutable}, |
| 17 | Pauli, PauliBinaryOps, PauliBits, PauliMutable, PauliNeutralElement, PauliUnitary, |
| 18 | PauliUnitaryProjective, |
| 19 | }; |
| 20 | |
| 21 | impl<BitsLeft, PhaseLeft, PauliRight: Pauli<PhaseExponentValue = u8>> MulAssign<&PauliRight> |
| 22 | for PauliUnitary<BitsLeft, PhaseLeft> |
| 23 | where |
| 24 | PauliUnitary<BitsLeft, PhaseLeft>: PauliBinaryOps<PauliRight>, |
| 25 | BitsLeft: PauliBits, |
| 26 | PhaseLeft: PhaseExponent, |
| 27 | { |
| 28 | fn mul_assign(&mut self, other: &PauliRight) { |
| 29 | self.mul_assign_right(other); |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | impl<BitsLeft, PauliRight: Pauli<PhaseExponentValue = u8>> MulAssign<&PauliRight> |
| 34 | for PauliUnitaryProjective<BitsLeft> |
| 35 | where |
| 36 | PauliUnitaryProjective<BitsLeft>: PauliBinaryOps<PauliRight>, |
| 37 | BitsLeft: PauliBits, |
| 38 | { |
| 39 | fn mul_assign(&mut self, other: &PauliRight) { |
| 40 | self.mul_assign_right(other); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | pub struct Phase<Exponent: PhaseExponent>(Exponent); |
| 45 | |
| 46 | impl<Exponent: PhaseExponent> Phase<Exponent> { |
| 47 | pub fn from_exponent(exponent: Exponent) -> Self { |
| 48 | Self(exponent) |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | // Multiply an object by a reference on the right, consume the object return multiplication result |
| 53 | impl<BitsLeft, PhaseLeft, PauliRight: Pauli<PhaseExponentValue = u8>> Mul<&PauliRight> |
| 54 | for PauliUnitary<BitsLeft, PhaseLeft> |
| 55 | where |
| 56 | PauliUnitary<BitsLeft, PhaseLeft>: for<'a> MulAssign<&'a PauliRight>, |
| 57 | BitsLeft: PauliBits, |
| 58 | PhaseLeft: PhaseExponent, |
| 59 | { |
| 60 | type Output = PauliUnitary<BitsLeft, PhaseLeft>; |
| 61 | |
| 62 | fn mul(mut self, other: &PauliRight) -> Self::Output { |
| 63 | self *= other; |
| 64 | self |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | impl<BitsLeft, PauliRight: Pauli<PhaseExponentValue = u8>> Mul<&PauliRight> |
| 69 | for PauliUnitaryProjective<BitsLeft> |
| 70 | where |
| 71 | PauliUnitaryProjective<BitsLeft>: for<'a> MulAssign<&'a PauliRight>, |
| 72 | BitsLeft: PauliBits, |
| 73 | { |
| 74 | type Output = PauliUnitaryProjective<BitsLeft>; |
| 75 | |
| 76 | fn mul(mut self, other: &PauliRight) -> Self::Output { |
| 77 | self *= other; |
| 78 | self |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | // Multiply an object by a reference on the left, consume the object return multiplication result |
| 83 | |
| 84 | impl<BitsLeft, PhaseLeft, PauliRight: Pauli<PhaseExponentValue = u8>> Mul<PauliRight> |
| 85 | for &PauliUnitary<BitsLeft, PhaseLeft> |
| 86 | where |
| 87 | PauliRight: PauliBinaryOps<PauliUnitary<BitsLeft, PhaseLeft>>, |
| 88 | BitsLeft: PauliBits, |
| 89 | PhaseLeft: PhaseExponent, |
| 90 | { |
| 91 | type Output = PauliRight; |
| 92 | |
| 93 | fn mul(self, mut other: PauliRight) -> Self::Output { |
| 94 | other.mul_assign_left(self); |
| 95 | other |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | impl<BitsLeft, PauliRight: Pauli<PhaseExponentValue = ()>> Mul<PauliRight> |
| 100 | for &PauliUnitaryProjective<BitsLeft> |
| 101 | where |
| 102 | PauliRight: PauliBinaryOps<PauliUnitaryProjective<BitsLeft>>, |
| 103 | BitsLeft: PauliBits, |
| 104 | { |
| 105 | type Output = PauliRight; |
| 106 | |
| 107 | fn mul(self, mut other: PauliRight) -> Self::Output { |
| 108 | other.mul_assign_left(self); |
| 109 | other |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | // Multiplying by a phase |
| 114 | |
| 115 | impl<Bits: PauliBits, _Phase: PhaseExponentMutable, Exponent: PhaseExponent> |
| 116 | MulAssign<Phase<Exponent>> for PauliUnitary<Bits, _Phase> |
| 117 | where |
| 118 | PauliUnitary<Bits, _Phase>: PauliMutable + Pauli<PhaseExponentValue = u8>, |
| 119 | { |
| 120 | fn mul_assign(&mut self, phase: Phase<Exponent>) { |
| 121 | self.add_assign_phase_exp(phase.0.raw_value()); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | impl<Bits: PauliBits, _Phase: PhaseExponentMutable, Exponent: PhaseExponent> Mul<Phase<Exponent>> |
| 126 | for PauliUnitary<Bits, _Phase> |
| 127 | where |
| 128 | PauliUnitary<Bits, _Phase>: PauliMutable + Pauli<PhaseExponentValue = u8>, |
| 129 | { |
| 130 | type Output = PauliUnitary<Bits, _Phase>; |
| 131 | |
| 132 | fn mul(mut self, phase: Phase<Exponent>) -> Self::Output { |
| 133 | self.add_assign_phase_exp(phase.0.raw_value()); |
| 134 | self |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | impl<BitsLeft, PhaseLeft, BitsRight, PhaseRight> Mul<&PauliUnitary<BitsRight, PhaseRight>> |
| 139 | for &PauliUnitary<BitsLeft, PhaseLeft> |
| 140 | where |
| 141 | PauliUnitary<BitsLeft, PhaseLeft>: PauliNeutralElement, |
| 142 | <PauliUnitary<BitsLeft, PhaseLeft> as NeutralElement>::NeutralElementType: |
| 143 | PauliBinaryOps<PauliUnitary<BitsRight, PhaseRight>>, |
| 144 | BitsRight: PauliBits, |
| 145 | PhaseRight: PhaseExponent, |
| 146 | BitsLeft: PauliBits, |
| 147 | PhaseLeft: PhaseExponent, |
| 148 | { |
| 149 | type Output = <PauliUnitary<BitsLeft, PhaseLeft> as NeutralElement>::NeutralElementType; |
| 150 | |
| 151 | fn mul(self, other: &PauliUnitary<BitsRight, PhaseRight>) -> Self::Output { |
| 152 | let mut res = <PauliUnitary<BitsLeft, PhaseLeft> as NeutralElement>::neutral_element(self); |
| 153 | res.assign(self); |
| 154 | res.mul_assign_right(other); |
| 155 | res |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | impl<BitsLeft, BitsRight> Mul<&PauliUnitaryProjective<BitsRight>> |
| 160 | for &PauliUnitaryProjective<BitsLeft> |
| 161 | where |
| 162 | PauliUnitaryProjective<BitsLeft>: PauliNeutralElement, |
| 163 | <PauliUnitaryProjective<BitsLeft> as NeutralElement>::NeutralElementType: |
| 164 | PauliBinaryOps<PauliUnitaryProjective<BitsRight>>, |
| 165 | BitsRight: PauliBits, |
| 166 | BitsLeft: PauliBits, |
| 167 | { |
| 168 | type Output = <PauliUnitaryProjective<BitsLeft> as NeutralElement>::NeutralElementType; |
| 169 | |
| 170 | fn mul(self, other: &PauliUnitaryProjective<BitsRight>) -> Self::Output { |
| 171 | let mut res = <PauliUnitaryProjective<BitsLeft> as NeutralElement>::neutral_element(self); |
| 172 | res.assign(self); |
| 173 | res.mul_assign_right(other); |
| 174 | res |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | // negating object consumes it and returns the negation |
| 179 | impl<Bits: PauliBits, Phase: PhaseExponentMutable> Neg for PauliUnitary<Bits, Phase> |
| 180 | where |
| 181 | PauliUnitary<Bits, Phase>: PauliMutable + Pauli<PhaseExponentValue = u8>, |
| 182 | { |
| 183 | type Output = Self; |
| 184 | fn neg(mut self) -> Self::Output { |
| 185 | self.add_assign_phase_exp(2u8); |
| 186 | self |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | impl<Bits: PauliBits> Neg for PauliUnitaryProjective<Bits> |
| 191 | where |
| 192 | PauliUnitaryProjective<Bits>: PauliMutable, |
| 193 | { |
| 194 | type Output = Self; |
| 195 | fn neg(self) -> Self::Output { |
| 196 | self |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | // negating object consumes it and returns the negation |
| 201 | impl<Bits: PauliBits + Clone, Phase: PhaseExponentMutable + Clone> Neg |
| 202 | for &PauliUnitary<Bits, Phase> |
| 203 | where |
| 204 | PauliUnitary<Bits, Phase>: PauliMutable + Pauli<PhaseExponentValue = u8>, |
| 205 | { |
| 206 | type Output = PauliUnitary<Bits, Phase>; |
| 207 | fn neg(self) -> Self::Output { |
| 208 | let mut res = self.clone(); |
| 209 | res.add_assign_phase_exp(2u8); |
| 210 | res |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | impl<Bits: PauliBits + Clone> Neg for &PauliUnitaryProjective<Bits> |
| 215 | where |
| 216 | PauliUnitaryProjective<Bits>: PauliMutable, |
| 217 | { |
| 218 | type Output = PauliUnitaryProjective<Bits>; |
| 219 | fn neg(self) -> Self::Output { |
| 220 | self.clone() |
| 221 | } |
| 222 | } |