microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.25.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/paulimer/src/pauli/sparse.rs

172lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use rustc_hash::FxHashMap;
5
6use crate::bits::{self, Bitwise, IndexAssignable, IndexSet};
7use crate::pauli::generic::{PauliCharacterError, PauliUnitary};
8use crate::quantum_core::{self, PositionedPauliObservable};
9
10use super::{Pauli, PauliUnitaryProjective};
11
12pub type SparsePauli = PauliUnitary<IndexSet, u8>;
13pub type SparsePauliProjective = PauliUnitaryProjective<IndexSet>;
14
15// Note: Can be improved using PauliMutable trait
16// Question: Should 'i' be interpreted as I or complex phase ?
17impl TryFrom<FxHashMap<usize, char>> for SparsePauli {
18 type Error = PauliCharacterError;
19
20 fn try_from(characters: FxHashMap<usize, char>) -> Result<Self, Self::Error> {
21 let mut x_bits = IndexSet::new();
22 let mut z_bits = IndexSet::new();
23 let mut exponent: u8 = 0;
24 for (index, character) in characters {
25 match character {
26 'X' | 'x' => x_bits.assign_index(index, true),
27 'Z' | 'z' => z_bits.assign_index(index, true),
28 'Y' | 'y' => {
29 exponent += 1;
30 x_bits.assign_index(index, true);
31 z_bits.assign_index(index, true);
32 }
33 'I' => {}
34 _ => return Err(PauliCharacterError {}),
35 }
36 }
37 Ok(SparsePauli::from_bits(x_bits, z_bits, exponent))
38 }
39}
40
41// Note: Allow repeated indicies so that conversion never fails and replace with generic that relies on PauliMutable
42impl From<&[PositionedPauliObservable]> for SparsePauli {
43 fn from(pauli_observable: &[PositionedPauliObservable]) -> Self {
44 let mut obs_copy = Vec::from(pauli_observable);
45 obs_copy.sort_unstable();
46 if obs_copy.len() > 1 {
47 for j in 0..obs_copy.len() - 1 {
48 assert!(
49 obs_copy[j].qubit_id < obs_copy[j + 1].qubit_id,
50 "Repeated qubit positions"
51 );
52 }
53 }
54
55 let mut x_indices = IndexSet::new();
56 let mut z_indices = IndexSet::new();
57 let mut phase = 0u8;
58
59 for quantum_core::PositionedPauliObservable {
60 qubit_id,
61 observable,
62 } in obs_copy
63 {
64 match observable {
65 quantum_core::PauliObservable::PlusI => (),
66 quantum_core::PauliObservable::MinusI => phase += 2,
67 quantum_core::PauliObservable::PlusX => x_indices.assign_index(qubit_id, true),
68 quantum_core::PauliObservable::PlusZ => z_indices.assign_index(qubit_id, true),
69 quantum_core::PauliObservable::MinusX => {
70 x_indices.assign_index(qubit_id, true);
71 phase += 2;
72 }
73 quantum_core::PauliObservable::MinusZ => {
74 z_indices.assign_index(qubit_id, true);
75 phase += 2;
76 }
77 quantum_core::PauliObservable::PlusY => {
78 x_indices.assign_index(qubit_id, true);
79 z_indices.assign_index(qubit_id, true);
80 phase += 1;
81 }
82 quantum_core::PauliObservable::MinusY => {
83 x_indices.assign_index(qubit_id, true);
84 z_indices.assign_index(qubit_id, true);
85 phase += 3;
86 }
87 }
88 }
89 PauliUnitary::from_bits(x_indices, z_indices, phase)
90 }
91}
92
93impl From<&[PositionedPauliObservable]> for SparsePauliProjective {
94 fn from(pauli_observable: &[PositionedPauliObservable]) -> Self {
95 let mut obs_copy = Vec::from(pauli_observable);
96 obs_copy.sort_unstable();
97 if obs_copy.len() > 1 {
98 for j in 0..obs_copy.len() - 1 {
99 assert!(
100 obs_copy[j].qubit_id < obs_copy[j + 1].qubit_id,
101 "Repeated qubit positions"
102 );
103 }
104 }
105
106 let mut x_indices = IndexSet::new();
107 let mut z_indices = IndexSet::new();
108
109 for quantum_core::PositionedPauliObservable {
110 qubit_id,
111 observable,
112 } in obs_copy
113 {
114 match observable {
115 quantum_core::PauliObservable::PlusI | quantum_core::PauliObservable::MinusI => (),
116 quantum_core::PauliObservable::PlusX | quantum_core::PauliObservable::MinusX => {
117 x_indices.assign_index(qubit_id, true);
118 }
119 quantum_core::PauliObservable::PlusZ | quantum_core::PauliObservable::MinusZ => {
120 z_indices.assign_index(qubit_id, true);
121 }
122 quantum_core::PauliObservable::PlusY | quantum_core::PauliObservable::MinusY => {
123 x_indices.assign_index(qubit_id, true);
124 z_indices.assign_index(qubit_id, true);
125 }
126 }
127 }
128 PauliUnitaryProjective::from_bits(x_indices, z_indices)
129 }
130}
131
132impl<const LENGTH: usize> From<[PositionedPauliObservable; LENGTH]> for SparsePauli {
133 fn from(pauli_observable: [PositionedPauliObservable; LENGTH]) -> Self {
134 pauli_observable.as_slice().into()
135 }
136}
137
138impl From<Vec<PositionedPauliObservable>> for SparsePauli {
139 fn from(value: Vec<PositionedPauliObservable>) -> Self {
140 value.as_slice().into()
141 }
142}
143
144impl<const LENGTH: usize> From<[PositionedPauliObservable; LENGTH]> for SparsePauliProjective {
145 fn from(pauli_observable: [PositionedPauliObservable; LENGTH]) -> Self {
146 pauli_observable.as_slice().into()
147 }
148}
149
150impl From<Vec<PositionedPauliObservable>> for SparsePauliProjective {
151 fn from(value: Vec<PositionedPauliObservable>) -> Self {
152 value.as_slice().into()
153 }
154}
155
156pub fn remapped_sparse(pauli: &SparsePauli, support: &[usize]) -> SparsePauli {
157 let x_bits: IndexSet = bits::remapped(pauli.x_bits(), support);
158 let z_bits: IndexSet = bits::remapped(pauli.z_bits(), support);
159 SparsePauli::from_bits(x_bits, z_bits, pauli.xz_phase_exponent())
160}
161
162pub fn as_sparse(pauli: &impl Pauli<PhaseExponentValue = u8>) -> SparsePauli {
163 let x_bits = pauli.x_bits().support().into();
164 let z_bits = pauli.z_bits().support().into();
165 SparsePauli::from_bits(x_bits, z_bits, pauli.xz_phase_exponent())
166}
167
168pub fn as_sparse_projective(pauli: &impl Pauli) -> SparsePauliProjective {
169 let x_bits = pauli.x_bits().support().into();
170 let z_bits = pauli.z_bits().support().into();
171 SparsePauliProjective::from_bits(x_bits, z_bits)
172}
173