LCOV - code coverage report
Current view: top level - src/operations - measurement_operations.rs (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 119 123 96.7 %
Date: 2021-11-09 13:25:48 Functions: 84 84 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             : //! Collection of roqoqo measurement operations.
      14             : 
      15             : use qoqo_calculator::Calculator;
      16             : use std::collections::{HashMap, HashSet};
      17             : 
      18             : use crate::operations::{
      19             :     InvolveQubits, InvolvedQubits, Operate, OperatePragma, OperateSingleQubit, RoqoqoError,
      20             :     Substitute,
      21             : };
      22             : use crate::Circuit;
      23             : 
      24             : /// Measurement gate operation.
      25             : ///
      26             : /// This Operation acts on one qubit writing the result of the measurement into a readout.
      27             : /// The classical register for the readout needs to be defined in advance by using a Definition operation.
      28             : ///
      29             : /// # Note
      30             : ///
      31             : /// Here, it is a measurement in terms of quantum mechanics. The obtained result of a $\textit{single}$ measurement will be either a `0` or a `1`.  
      32             : /// In order to be able to derive probabilities in the $\textit{post-processing}$, the actual measurement needs to be repeated lots of times.
      33             : ///
      34             : #[derive(
      35           1 :     Debug,
      36           1 :     Clone,
      37           7 :     PartialEq,
      38           1 :     roqoqo_derive::InvolveQubits,
      39          15 :     roqoqo_derive::Operate,
      40           2 :     roqoqo_derive::Substitute,
      41           2 :     roqoqo_derive::OperateSingleQubit,
      42             : )]
      43             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
      44             : pub struct MeasureQubit {
      45             :     /// The measured qubit.
      46             :     qubit: usize,
      47             :     /// The register for the readout.
      48             :     readout: String,
      49             :     /// The index in the readout the result is saved to.
      50             :     readout_index: usize,
      51             : }
      52             : 
      53             : #[allow(non_upper_case_globals)]
      54             : const TAGS_MeasureQubit: &[&str; 3] = &["Operation", "Measurement", "MeasureQubit"];
      55             : 
      56             : /// This PRAGMA measurement operation returns the statevector of a quantum register.
      57             : ///
      58           8 : #[derive(Debug, Clone, PartialEq, roqoqo_derive::Operate, roqoqo_derive::OperatePragma)]
      59             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
      60             : pub struct PragmaGetStateVector {
      61             :     /// The name of the classical readout register.
      62             :     readout: String,
      63             :     /// The measurement preparation Circuit, applied on a copy of the register before measurement (None if not defined, Some(Circuit) otherwise).
      64             :     circuit: Option<Circuit>,
      65             : }
      66             : 
      67             : #[allow(non_upper_case_globals)]
      68             : const TAGS_PragmaGetStateVector: &[&str; 4] = &[
      69             :     "Operation",
      70             :     "Measurement",
      71             :     "PragmaOperation",
      72             :     "PragmaGetStateVector",
      73             : ];
      74             : 
      75             : /// Implements [Substitute] trait allowing to replace symbolic parameters and to perform qubit mappings.
      76             : impl Substitute for PragmaGetStateVector {
      77             :     /// Remaps qubits in operations in clone of the operation.
      78           2 :     fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
      79           2 :         let new_circuit = match self.circuit.as_ref() {
      80           1 :             Some(x) => Some(x.remap_qubits(mapping)?),
      81           1 :             _ => None,
      82             :         };
      83           2 :         Ok(PragmaGetStateVector::new(self.readout.clone(), new_circuit))
      84           2 :     }
      85             : 
      86             :     /// Substitutes symbolic parameters in clone of the operation.
      87           1 :     fn substitute_parameters(&self, calculator: &mut Calculator) -> Result<Self, RoqoqoError> {
      88           1 :         let new_circuit = match self.circuit.as_ref() {
      89           0 :             Some(x) => Some(x.substitute_parameters(calculator)?),
      90           1 :             _ => None,
      91             :         };
      92           1 :         Ok(PragmaGetStateVector::new(self.readout.clone(), new_circuit))
      93           1 :     }
      94             : }
      95             : 
      96             : // Implements the InvolveQubits trait for PragmaGetStateVector.
      97             : impl InvolveQubits for PragmaGetStateVector {
      98             :     /// Lists all involved qubits (here: All).
      99           1 :     fn involved_qubits(&self) -> InvolvedQubits {
     100           1 :         InvolvedQubits::All
     101           1 :     }
     102             : }
     103             : 
     104             : /// This PRAGMA measurement operation returns the density matrix of a quantum register.
     105             : ///
     106           8 : #[derive(Debug, Clone, PartialEq, roqoqo_derive::Operate, roqoqo_derive::OperatePragma)]
     107             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     108             : pub struct PragmaGetDensityMatrix {
     109             :     /// The name of the classical readout register.
     110             :     readout: String,
     111             :     /// The measurement preparation Circuit, applied on a copy of the register before measurement (None if not defined, Some(Circuit) otherwise).
     112             :     circuit: Option<Circuit>,
     113             : }
     114             : 
     115             : #[allow(non_upper_case_globals)]
     116             : const TAGS_PragmaGetDensityMatrix: &[&str; 4] = &[
     117             :     "Operation",
     118             :     "Measurement",
     119             :     "PragmaOperation",
     120             :     "PragmaGetDensityMatrix",
     121             : ];
     122             : 
     123             : /// Implements [Substitute] trait allowing to replace symbolic parameters and to perform qubit mappings.
     124             : impl Substitute for PragmaGetDensityMatrix {
     125             :     /// Remaps qubits in operations in clone of the operation.
     126           2 :     fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
     127           2 :         let new_circuit = match self.circuit.as_ref() {
     128           1 :             Some(x) => Some(x.remap_qubits(mapping)?),
     129           1 :             _ => None,
     130             :         };
     131           2 :         Ok(PragmaGetDensityMatrix::new(
     132           2 :             self.readout.clone(),
     133           2 :             new_circuit,
     134           2 :         ))
     135           2 :     }
     136             : 
     137             :     /// Substitutes symbolic parameters in clone of the operation.
     138           1 :     fn substitute_parameters(&self, calculator: &mut Calculator) -> Result<Self, RoqoqoError> {
     139           1 :         let new_circuit = match self.circuit.as_ref() {
     140           0 :             Some(x) => Some(x.substitute_parameters(calculator)?),
     141           1 :             _ => None,
     142             :         };
     143           1 :         Ok(PragmaGetDensityMatrix::new(
     144           1 :             self.readout.clone(),
     145           1 :             new_circuit,
     146           1 :         ))
     147           1 :     }
     148             : }
     149             : 
     150             : // Implements the InvolveQubits trait for PragmaGetDensityMatrix.
     151             : impl InvolveQubits for PragmaGetDensityMatrix {
     152             :     /// Lists all involved qubits (here, all).
     153           1 :     fn involved_qubits(&self) -> InvolvedQubits {
     154           1 :         InvolvedQubits::All
     155           1 :     }
     156             : }
     157             : 
     158             : /// This PRAGMA measurement operation returns the vector of the occupation probabilities.
     159             : ///
     160             : /// Occupation probabilities in the context of this PRAGMA Operation are probabilities of finding the quantum
     161             : /// register in each $\sigma_z$ basis state. The quantum register remains unchanged by this PRAGMA measurement operation.
     162             : ///
     163           8 : #[derive(Debug, Clone, PartialEq, roqoqo_derive::Operate, roqoqo_derive::OperatePragma)]
     164             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     165             : pub struct PragmaGetOccupationProbability {
     166             :     /// The name of the classical readout register.
     167             :     readout: String,
     168             :     /// The measurement preparation Circuit, applied on a copy of the register before measurement (None if not defined, Some(Circuit) otherwise).
     169             :     circuit: Option<Circuit>,
     170             : }
     171             : 
     172             : #[allow(non_upper_case_globals)]
     173             : const TAGS_PragmaGetOccupationProbability: &[&str; 4] = &[
     174             :     "Operation",
     175             :     "Measurement",
     176             :     "PragmaOperation",
     177             :     "PragmaGetOccupationProbability",
     178             : ];
     179             : 
     180             : /// Implements [Substitute] trait allowing to replace symbolic parameters and to perform qubit mappings.
     181             : impl Substitute for PragmaGetOccupationProbability {
     182             :     /// Remaps qubits in operations in clone of the operation.
     183           2 :     fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
     184           2 :         let new_circuit = match self.circuit.as_ref() {
     185           1 :             Some(x) => Some(x.remap_qubits(mapping)?),
     186           1 :             _ => None,
     187             :         };
     188           2 :         Ok(PragmaGetOccupationProbability::new(
     189           2 :             self.readout.clone(),
     190           2 :             new_circuit,
     191           2 :         ))
     192           2 :     }
     193             : 
     194             :     /// Substitutes symbolic parameters in clone of the operation.
     195           1 :     fn substitute_parameters(&self, calculator: &mut Calculator) -> Result<Self, RoqoqoError> {
     196           1 :         let new_circuit = match self.circuit.as_ref() {
     197           0 :             Some(x) => Some(x.substitute_parameters(calculator)?),
     198           1 :             _ => None,
     199             :         };
     200           1 :         Ok(PragmaGetOccupationProbability::new(
     201           1 :             self.readout.clone(),
     202           1 :             new_circuit,
     203           1 :         ))
     204           1 :     }
     205             : }
     206             : 
     207             : // Implements the InvolveQubits trait for PragmaGetOccupationProbability.
     208             : impl InvolveQubits for PragmaGetOccupationProbability {
     209             :     /// Lists all involved qubits (here, all).
     210           2 :     fn involved_qubits(&self) -> InvolvedQubits {
     211           2 :         InvolvedQubits::All
     212           2 :     }
     213             : }
     214             : 
     215             : /// This PRAGMA measurement operation returns a Pauli product expectation value.
     216             : ///
     217             : /// This PRAGMA Operation returns a Pauli product expectation value after applying
     218             : /// a Rotate to another basis. It performs all of the operation on a clone of the quantum register,
     219             : /// so that the actual quantum register remains unchanged.
     220             : ///
     221          19 : #[derive(Debug, Clone, PartialEq, roqoqo_derive::Operate, roqoqo_derive::OperatePragma)]
     222             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     223             : pub struct PragmaGetPauliProduct {
     224             :     /// The HashMap of the pauli matrix to apply to each qubit in the form {qubit: pauli}. Allowed values to be provided for 'pauli' are: `0` = identity, `1` = PauliX, `2` = PauliY, `3` = PauliZ.
     225             :     qubit_paulis: HashMap<usize, usize>,
     226             :     /// The name of the classical readout register.
     227             :     readout: String,
     228             :     /// The measurement preparation Circuit, applied on a copy of the register before measurement.
     229             :     circuit: Circuit,
     230             : }
     231             : 
     232             : #[allow(non_upper_case_globals)]
     233             : const TAGS_PragmaGetPauliProduct: &[&str; 4] = &[
     234             :     "Operation",
     235             :     "Measurement",
     236             :     "PragmaOperation",
     237             :     "PragmaGetPauliProduct",
     238             : ];
     239             : 
     240             : /// Implements [Substitute] trait allowing to replace symbolic parameters and to perform qubit mappings.
     241             : impl Substitute for PragmaGetPauliProduct {
     242             :     /// Remaps qubits in operations in clone of the operation.
     243           2 :     fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
     244           2 :         let mut mutable_mapping: HashMap<usize, usize> = self.qubit_paulis.clone();
     245           4 :         for (old_qubit, new_qubit) in mapping {
     246           2 :             if let Some(v) = mutable_mapping.remove(old_qubit) {
     247           2 :                 mutable_mapping.insert(*new_qubit, v);
     248           2 :             }
     249             :         }
     250           2 :         let new_circuit = self.circuit.remap_qubits(mapping).unwrap();
     251           2 :         Ok(PragmaGetPauliProduct::new(
     252           2 :             mutable_mapping,
     253           2 :             self.readout.clone(),
     254           2 :             new_circuit,
     255           2 :         ))
     256           2 :     }
     257             : 
     258             :     /// Substitutes symbolic parameters in clone of the operation.
     259           1 :     fn substitute_parameters(&self, calculator: &mut Calculator) -> Result<Self, RoqoqoError> {
     260           1 :         let new_circuit = self.circuit.substitute_parameters(calculator).unwrap();
     261           1 :         Ok(PragmaGetPauliProduct::new(
     262           1 :             self.qubit_paulis.clone(),
     263           1 :             self.readout.clone(),
     264           1 :             new_circuit,
     265           1 :         ))
     266           1 :     }
     267             : }
     268             : 
     269             : // Implements the InvolveQubits trait for PragmaGetPauliProduct.
     270             : impl InvolveQubits for PragmaGetPauliProduct {
     271             :     /// Lists all involved qubits.
     272           1 :     fn involved_qubits(&self) -> InvolvedQubits {
     273           1 :         let mut new_hash_set: HashSet<usize> = HashSet::new();
     274           1 :         for qubit in self.qubit_paulis.keys() {
     275           1 :             new_hash_set.insert(*qubit);
     276           1 :         }
     277           1 :         if let InvolvedQubits::Set(tmp_set) = &self.circuit.involved_qubits() {
     278           1 :             for qubit in tmp_set {
     279           1 :                 new_hash_set.insert(*qubit);
     280           1 :             }
     281           0 :         }
     282           1 :         InvolvedQubits::Set(new_hash_set)
     283           1 :     }
     284             : }
     285             : 
     286             : /// This PRAGMA measurement operation returns a measurement record for $N$ repeated measurements.
     287             : ///
     288          15 : #[derive(Debug, Clone, PartialEq, roqoqo_derive::Operate, roqoqo_derive::OperatePragma)]
     289             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     290             : pub struct PragmaRepeatedMeasurement {
     291             :     /// The name of the classical readout register.
     292             :     readout: String,
     293             :     /// The number of times $N$ to repeat the measurement.
     294             :     number_measurements: usize,
     295             :     /// The mapping of qubits to indices in the readout register.
     296             :     qubit_mapping: Option<HashMap<usize, usize>>,
     297             : }
     298             : 
     299             : #[allow(non_upper_case_globals)]
     300             : const TAGS_PragmaRepeatedMeasurement: &[&str; 4] = &[
     301             :     "Operation",
     302             :     "Measurement",
     303             :     "PragmaOperation",
     304             :     "PragmaRepeatedMeasurement",
     305             : ];
     306             : 
     307             : /// Implements [Substitute] trait allowing to replace symbolic parameters and to perform qubit mappings.
     308             : impl Substitute for PragmaRepeatedMeasurement {
     309             :     /// Remaps qubits in operations in clone of the operation.
     310           1 :     fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
     311           1 :         let new_mapping = (self.qubit_mapping.clone()).map(|hm| {
     312           1 :             let mut mutable_mapping: HashMap<usize, usize> = hm;
     313           2 :             for (old_qubit, new_qubit) in mapping {
     314           1 :                 if let Some(v) = mutable_mapping.remove(old_qubit) {
     315           1 :                     mutable_mapping.insert(*new_qubit, v);
     316           1 :                 }
     317             :             }
     318           1 :             mutable_mapping
     319           1 :         });
     320           1 :         Ok(PragmaRepeatedMeasurement::new(
     321           1 :             self.readout.clone(),
     322           1 :             self.number_measurements,
     323           1 :             new_mapping,
     324           1 :         ))
     325           1 :     }
     326             : 
     327             :     /// Substitutes symbolic parameters in clone of the operation.
     328           1 :     fn substitute_parameters(&self, _calculator: &mut Calculator) -> Result<Self, RoqoqoError> {
     329           1 :         Ok(self.clone())
     330           1 :     }
     331             : }
     332             : 
     333             : // Implements the InvolveQubits trait for PragmaRepeatedMeasurement.
     334             : impl InvolveQubits for PragmaRepeatedMeasurement {
     335             :     /// Lists all involved qubits (here, all).
     336           1 :     fn involved_qubits(&self) -> InvolvedQubits {
     337           1 :         InvolvedQubits::All
     338           1 :     }
     339             : }

Generated by: LCOV version 1.13