Line data Source code
1 : // Copyright © 2021 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 :
13 : use crate::CalculatorFloat;
14 : use crate::RoqoqoError;
15 : use num_complex::Complex64;
16 : use std::collections::HashMap;
17 :
18 : /// Provides PauliProductMasks for all Pauli Products measured from one readout register.
19 : pub type SingleReadoutPauliProductMasks = HashMap<usize, PauliProductMask>;
20 :
21 : /// Provides Mask for a single PauliProduct.
22 : pub type PauliProductMask = Vec<usize>;
23 :
24 : /// Defines how Pauli Products expectation values are post-processed into observable expectation value.
25 2 : #[derive(Debug, Clone, PartialEq)]
26 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
27 : pub enum PauliProductsToExpVal {
28 : /// Expectation value of observable is a linear combination of Pauli Product expectation values.
29 : ///
30 : /// Only scalar real expectation values are supported.
31 : /// For complex observables or vector/matrix observables
32 : /// components have to be postprocessed separately.
33 : Linear(HashMap<usize, f64>),
34 : /// Expectation value of observable is derived from symbolic expression.
35 : ///
36 : /// Symbolic expression is given by [qoqo_calculator::CalculatorFloat]
37 : /// The i-th PauliProduct us hardcoded as the variable `pauli_product_i`
38 : /// in the string expression of CalculatorFloat.
39 : Symbolic(CalculatorFloat),
40 : }
41 :
42 : /// Provides Necessary Information to run a [crate::measurements::BasisRotation] measurement.
43 : ///
44 : /// BasisRotationInput is the input struct for a BasisRotation measurement, dictating which expectation
45 : /// values are measured by BasisRotation. These expecation values are defined as
46 : /// expectation values of pauli products.
47 5 : #[derive(Debug, Clone, PartialEq)]
48 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
49 : pub struct BasisRotationInput {
50 : /// Collection of PauliProductMasks for each readout register in Measurement.
51 : pub pauli_product_qubit_masks: HashMap<String, SingleReadoutPauliProductMasks>,
52 : /// Number of qubits that are measured.
53 : pub number_qubits: usize,
54 : /// Number of Pauli Products that are measured.
55 : pub number_pauli_products: usize,
56 : /// Collection of names and construction methods of expectation values.
57 : ///
58 : /// The construction methods are given by [PauliProductsToExpVal] enums.
59 : pub measured_exp_vals: HashMap<String, PauliProductsToExpVal>,
60 : /// Determines whether measurement errors are symmetrized.
61 : ///
62 : /// Measurement errors are symmetrized by repeating measurement with final flip of all qubits.
63 : pub use_flipped_measurement: bool,
64 : }
65 :
66 : impl BasisRotationInput {
67 : /// Creates new BasisRotationInput.
68 : ///
69 : /// The BasisRotationInput starts with just the number of qubtis and flipped measurements set.
70 : /// The pauli_product_qubit_masks and measured_exp_vals start empty
71 : /// and can be extended with [BasisRotationInput::add_pauli_product],
72 : /// [BasisRotationInput::add_linear_exp_val] and [BasisRotationInput::add_symbolic_exp_val].
73 : ///
74 : /// # Arguments
75 : ///
76 : /// * `number_qubits` - The number of qubits in the BasisRotation measurement.
77 : /// * `use_flipped_measurement` - Whether or not to use flipped measurements.
78 : ///
79 19 : pub fn new(number_qubits: usize, use_flipped_measurement: bool) -> Self {
80 19 : Self {
81 19 : pauli_product_qubit_masks: HashMap::new(),
82 19 : number_qubits,
83 19 : number_pauli_products: 0,
84 19 : measured_exp_vals: HashMap::new(),
85 19 : use_flipped_measurement,
86 19 : }
87 19 : }
88 :
89 : /// Adds measured Pauli product to BasisRotationInput and returns index of Pauli product.
90 : ///
91 : /// When the pauli product is already in the measurement input the function only returns
92 : /// it index.
93 : ///
94 : /// # Arguments
95 : ///
96 : /// * `readout` - The name of the readout register the pauli_product is defined on.
97 : /// * `pauli_product_mask` - The list of the qubits involved in the Pauli product measurement.
98 : ///
99 : /// # Returns
100 : ///
101 : /// * `Ok(usize)` - The index of the added Pauli product in the list of all Pauli products.
102 : /// * `Err([RoqoqoError::PauliProductExceedsQubits])` - The pauli product involves a qubit exceeding the maximum number of qubits.
103 : pub fn add_pauli_product(
104 : &mut self,
105 : readout: String,
106 : pauli_product_mask: PauliProductMask,
107 : ) -> Result<usize, RoqoqoError> {
108 41 : if let Some(i) = &pauli_product_mask
109 41 : .iter()
110 47 : .find(|i| i >= &&self.number_qubits)
111 : {
112 1 : return Err(RoqoqoError::PauliProductExceedsQubits {
113 1 : pp_qubit: **i,
114 1 : number_qubits: self.number_qubits,
115 1 : });
116 40 : }
117 :
118 : // Readout already in pauli_product_qubit_masks
119 40 : if let Some(m) = self.pauli_product_qubit_masks.get_mut(&readout) {
120 : // Check if PauliProduct has already been added
121 33 : if let Some((k, _)) = m.iter().find(|(_, v)| v == &&pauli_product_mask) {
122 1 : return Ok(*k);
123 21 : }
124 21 : m.insert(self.number_pauli_products, pauli_product_mask);
125 18 : } else {
126 18 : // Readout not yet in pauli_product_qubit_masks
127 18 : let mut new_map = HashMap::new();
128 18 : new_map.insert(self.number_pauli_products, pauli_product_mask);
129 18 : self.pauli_product_qubit_masks.insert(readout, new_map);
130 18 : }
131 39 : self.number_pauli_products += 1;
132 39 :
133 39 : Ok(self.number_pauli_products - 1)
134 41 : }
135 :
136 : /// Adds linear definition of expectation value to measurement input.
137 : ///
138 : /// Adds an expectation value that is defined by a linear combination
139 : /// of expectation values of Pauli products.
140 : ///
141 : /// # Arguments
142 : ///
143 : /// * `name` - The name of the expectation value.
144 : /// * `linear` - The linear combination of expectation values as a map between Pauli product index and coefficient.
145 : ///
146 : /// # Returns
147 : ///
148 : /// * `Ok()` - The value was successfully added.
149 : /// * `Err([RoqoqoError::ExpValUsedTwice])` - The name of expectation value is already taken.
150 29 : pub fn add_linear_exp_val(
151 29 : &mut self,
152 29 : name: String,
153 29 : linear: HashMap<usize, f64>,
154 29 : ) -> Result<(), RoqoqoError> {
155 29 : if self
156 29 : .measured_exp_vals
157 29 : .insert(name.clone(), PauliProductsToExpVal::Linear(linear))
158 29 : .is_some()
159 : {
160 1 : return Err(RoqoqoError::ExpValUsedTwice { name });
161 28 : }
162 28 : Ok(())
163 29 : }
164 :
165 : /// Adds symbolic definition of expectation value to measurement input.
166 : ///
167 : /// Adds an expectation value that is defined by a symbolic combination
168 : /// of expectation values of Pauli products.
169 : ///
170 : /// # Arguments
171 : ///
172 : /// * `name` - The name of the expectation value.
173 : /// * `symbolic` - The symbolic expression for the expectation values
174 : /// given by [qoqo_calculator::CalculatorFloat].
175 : ///
176 : /// The i-th PauliProduct is hardcoded as variable `pauli_product_i`
177 : /// in the string expression of CalculatorFloat.
178 : ///
179 : /// # Returns
180 : ///
181 : /// * `Ok()` - The value was successfully added.
182 : /// * `Err([RoqoqoError::ExpValUsedTwice])` - The name of expectation value is already taken.
183 4 : pub fn add_symbolic_exp_val(
184 4 : &mut self,
185 4 : name: String,
186 4 : symbolic: CalculatorFloat,
187 4 : ) -> Result<(), RoqoqoError> {
188 4 : if self
189 4 : .measured_exp_vals
190 4 : .insert(name.clone(), PauliProductsToExpVal::Symbolic(symbolic))
191 4 : .is_some()
192 : {
193 1 : return Err(RoqoqoError::ExpValUsedTwice { name });
194 3 : }
195 3 : Ok(())
196 4 : }
197 : }
198 :
199 : /// Provides necessary information to run a [crate::measurements::CheatedBasisRotation] measurement.
200 : ///
201 : /// Is used by the full measurement struct [crate::measurements::CheatedBasisRotation].
202 5 : #[derive(Debug, Clone, PartialEq)]
203 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
204 : pub struct CheatedBasisRotationInput {
205 : /// Collection of names and construction methods of expectation values.
206 : ///
207 : /// The construction methods are given by [PauliProductsToExpVal] enums.
208 : pub measured_exp_vals: HashMap<String, PauliProductsToExpVal>,
209 : /// Mapping the pauli product indices to the readout keys.
210 : pub pauli_product_keys: HashMap<String, usize>,
211 : }
212 :
213 : impl Default for CheatedBasisRotationInput {
214 : /// Creates a default (here, new) instance of CheatedBasisRotationInput.
215 1 : fn default() -> Self {
216 1 : Self::new()
217 1 : }
218 : }
219 :
220 : impl CheatedBasisRotationInput {
221 : /// Creates new CheatedBasisRotationInput.
222 : ///
223 : /// # Returns
224 : ///
225 : /// * `Self` - The new instance of CheatedBasisRotationInput with measured_exp_vals = an empty
226 : /// HashMap and pauli_product_keys = an empty HashMap.
227 14 : pub fn new() -> Self {
228 14 : Self {
229 14 : measured_exp_vals: HashMap::new(),
230 14 : pauli_product_keys: HashMap::new(),
231 14 : }
232 14 : }
233 :
234 : /// Adds measured Pauli product to CheatedBasisRotationInput and returns index of Pauli product.
235 : ///
236 : /// When the pauli product is already in the measurement input the function only returns
237 : /// it index.
238 : ///
239 : /// # Arguments
240 : ///
241 : /// * `readout` - The name of the readout register containing the the pauli_product expecation value.
242 : ///
243 : /// # Returns
244 : ///
245 : /// * `usize` - The index of the added Pauli product in the list of all Pauli products.
246 : pub fn add_pauli_product(&mut self, readout: String) -> usize {
247 12 : if let Some((_, v)) = self.pauli_product_keys.iter().find(|(k, _)| k == &&readout) {
248 1 : return *v;
249 11 : }
250 11 : self.pauli_product_keys
251 11 : .insert(readout, self.pauli_product_keys.len());
252 11 : self.pauli_product_keys.len() - 1
253 12 : }
254 :
255 : /// Adds linear definition of expectation value to measurement input.
256 : ///
257 : /// Adds an expectation value that is defined by a linear combination
258 : /// of expectation values of Pauli products.
259 : ///
260 : /// # Arguments
261 : ///
262 : /// * `name` - The name of the expectation value.
263 : /// * `linear` - The linear combination of expectation values as a map between Pauli product index and coefficient.
264 : ///
265 : /// # Returns
266 : ///
267 : /// * `Ok()` - The value was successfully added.
268 : /// * `Err([RoqoqoError::ExpValUsedTwice])` - The name of expectation value already taken.
269 3 : pub fn add_linear_exp_val(
270 3 : &mut self,
271 3 : name: String,
272 3 : linear: HashMap<usize, f64>,
273 3 : ) -> Result<(), RoqoqoError> {
274 3 : if self
275 3 : .measured_exp_vals
276 3 : .insert(name.clone(), PauliProductsToExpVal::Linear(linear))
277 3 : .is_some()
278 : {
279 1 : return Err(RoqoqoError::ExpValUsedTwice { name });
280 2 : }
281 2 : Ok(())
282 3 : }
283 :
284 : /// Adds linear definition of expectation value to measurement input.
285 : ///
286 : /// Adds an expectation value that is defined by a linear combination
287 : /// of expectation values of Pauli products.
288 : ///
289 : /// # Arguments
290 : ///
291 : /// * `name` - The name of the expectation value.
292 : /// * `symbolic` - The symbolic expression for the expectation values
293 : /// given by [qoqo_calculator::CalculatorFloat].
294 : ///
295 : /// The i-th PauliProducts are hardcoded as variables pauli_product_i
296 : /// in the string expression of CalculatorFloat.
297 : ///
298 : /// # Returns
299 : ///
300 : /// * `Ok()` - The value was successfully added.
301 : /// * `Err([RoqoqoError::ExpValUsedTwice])` - The name of expectation value already taken.
302 3 : pub fn add_symbolic_exp_val(
303 3 : &mut self,
304 3 : name: String,
305 3 : symbolic: CalculatorFloat,
306 3 : ) -> Result<(), RoqoqoError> {
307 3 : if self
308 3 : .measured_exp_vals
309 3 : .insert(name.clone(), PauliProductsToExpVal::Symbolic(symbolic))
310 3 : .is_some()
311 : {
312 1 : return Err(RoqoqoError::ExpValUsedTwice { name });
313 2 : }
314 2 : Ok(())
315 3 : }
316 : }
317 :
318 : /// Provides necessary information to run a [crate::measurements::Cheated] measurement.
319 : ///
320 : /// Is used by the full measurement struct [crate::measurements::Cheated].
321 5 : #[derive(Debug, Clone, PartialEq)]
322 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
323 : pub struct CheatedInput {
324 : /// Map of expectation values and corresponding operator Matrices on the Hilbert Space.
325 : pub measured_operators: HashMap<String, (OperatorSparseVec, String)>,
326 : /// Number of qubits that defines the dimension of the Hilbertspace.
327 : pub number_qubits: usize,
328 : }
329 :
330 : /// Represents Operator acting on Hilbert space as a sparse list of two indices and a value.
331 : ///
332 : /// The vector contains the triplets of non-zero elements of the sparse matrix
333 : /// representing the operator on the Hilbert space.
334 : /// The first element is the row index, the second the column index and the last the
335 : /// complex value of the non-zero entry.
336 : pub type OperatorSparseVec = Vec<(usize, usize, Complex64)>;
337 :
338 : impl CheatedInput {
339 : /// Creates new CheatedInput.
340 : ///
341 : /// # Arguments
342 : ///
343 : /// * `number_qubits` - The number of qubits in the Cheated measurement.
344 : ///
345 : /// # Returns
346 : ///
347 : /// * `Self` - The new instance of CheatedInput with measured_operators = an empty HashMap and the
348 : /// specified number of qubits in input.
349 16 : pub fn new(number_qubits: usize) -> Self {
350 16 : Self {
351 16 : measured_operators: HashMap::new(),
352 16 : number_qubits,
353 16 : }
354 16 : }
355 :
356 : /// Adds expectation value of an operator to measurement input.
357 : ///
358 : /// Adds an expectation value of a quantum operator defined by a complex matrix.
359 : ///
360 : /// # Arguments
361 : ///
362 : /// * `name` - The name. of the expectation value
363 : /// * `operator` - The measured operator on the Hilbert space given as a list of sparse matrix entries of the form (row, col, value).
364 : /// * `readout` - The name of the readout register that contains the density matrix or satevector.
365 : ///
366 : /// # Returns
367 : ///
368 : /// * `Ok()` - The operator was successfully added.
369 : /// * `Err([RoqoqoError::MismatchedOperatorDimension])` - The index of operator exceeds Hilbert space dimension of qubits.
370 : /// * `Err([RoqoqoError::ExpValUsedTwice])` - The name of expectation value already taken.
371 19 : pub fn add_operator_exp_val(
372 19 : &mut self,
373 19 : name: String,
374 19 : operator: OperatorSparseVec,
375 19 : readout: String,
376 19 : ) -> Result<(), RoqoqoError> {
377 19 : let dimension = 2_usize.pow(self.number_qubits as u32);
378 19 : if let Some((x, y, _)) = operator
379 19 : .iter()
380 61 : .find(|(x, y, _)| x >= &dimension || y >= &dimension)
381 : {
382 1 : return Err(RoqoqoError::MismatchedOperatorDimension {
383 1 : index: (*x, *y),
384 1 : number_qubits: self.number_qubits,
385 1 : });
386 18 : }
387 18 : if self
388 18 : .measured_operators
389 18 : .insert(name.clone(), (operator, readout))
390 18 : .is_some()
391 : {
392 1 : return Err(RoqoqoError::ExpValUsedTwice { name });
393 17 : }
394 17 : Ok(())
395 19 : }
396 : }
|