LCOV - code coverage report
Current view: top level - src/measurements - measurement_auxiliary_data_input.rs (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 133 133 100.0 %
Date: 2021-11-09 13:25:48 Functions: 31 31 100.0 %

          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             : }

Generated by: LCOV version 1.13