LCOV - code coverage report
Current view: top level - src - backends.rs (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 26 42 61.9 %
Date: 2021-11-09 13:25:48 Functions: 7 7 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             : //! Traits defining the standard form of roqoqo backends.
      14             : //!
      15             : //! roqoqo can be used to implement interfaces and backends to quantum hardware, quantum simulators and other software packages.
      16             : //! While roqoqo does not require a certain design for general interfaces or backends,
      17             : //! roqoqo::backends provides a trait for implementing backends that produce measurement results which can be evaluated to
      18             : //! expectation values.
      19             : //! This trait is supposed to be implemented for backends connecting to quantum simulators or to real quantum hardware devices.
      20             : //!
      21             : //! Note: The following backends are implemented in roqoqo and supported by HQS Quantum Simulations GmbH.
      22             : //!
      23             : //! Evaluated backends:
      24             : //! * `aqt`,
      25             : //! * `MockedBackend` ( <https://github.com/HQSquantumsimulations/qoqo_mock> ),
      26             : //! * `PyQuestBackend` ( <https://github.com/HQSquantumsimulations/qoqo_pyquest> ).
      27             : //!
      28             : //! Other backends:
      29             : //! * `qasm` ( <https://github.com/HQSquantumsimulations/qoqo_qasm> ).
      30             : 
      31             : use std::collections::HashMap;
      32             : 
      33             : use crate::operations::Operation;
      34             : use crate::registers::{BitOutputRegister, ComplexOutputRegister, FloatOutputRegister};
      35             : use crate::Circuit;
      36             : use crate::{
      37             :     measurements::{Measure, MeasureExpectationValues},
      38             :     RoqoqoBackendError,
      39             : };
      40             : 
      41             : /// Result of functions running a full circuit and producing output registers.
      42             : pub type RegisterResult = Result<
      43             :     (
      44             :         HashMap<String, BitOutputRegister>,
      45             :         HashMap<String, FloatOutputRegister>,
      46             :         HashMap<String, ComplexOutputRegister>,
      47             :     ),
      48             :     RoqoqoBackendError,
      49             : >;
      50             : 
      51             : /// Trait for Backends that can evaluate measurements to expectation values.
      52             : pub trait EvaluatingBackend: Sized {
      53             :     /// Runs a circuit with the backend.
      54             :     ///
      55             :     /// A circuit is passed to the backend and executed.
      56             :     /// During execution values are written to and read from classical registers
      57             :     /// ([crate::registers::BitRegister], [crate::registers::FloatRegister] and [crate::registers::ComplexRegister]).
      58             :     /// To produce sufficient statistics for evaluating expectationg values,
      59             :     /// circuits have to be run multiple times.
      60             :     /// The results of each repetition are concatenated in OutputRegisters
      61             :     /// ([crate::registers::BitOutputRegister], [crate::registers::FloatOutputRegister] and [crate::registers::ComplexOutputRegister]).  
      62             :     ///
      63             :     ///
      64             :     /// # Arguments
      65             :     ///
      66             :     /// * `circuit` - The circuit that is run on the backend.
      67             :     ///
      68             :     /// # Returns
      69             :     ///
      70             :     /// `RegisterResult` - The output registers written by the evaluated circuits.
      71             :     fn run_circuit(&self, circuit: &Circuit) -> RegisterResult {
      72             :         self.run_circuit_iterator(circuit.iter())
      73             :     }
      74             : 
      75             :     /// Runs each operation obtained from an iterator over operations on the backend.
      76             :     ///
      77             :     /// An iterator over operations is passed to the backend and executed.
      78             :     /// During execution values are written to and read from classical registers
      79             :     /// ([crate::registers::BitRegister], [crate::registers::FloatRegister] and [crate::registers::ComplexRegister]).
      80             :     /// To produce sufficient statistics for evaluating expectationg values,
      81             :     /// circuits have to be run multiple times.
      82             :     /// The results of each repetition are concatenated in OutputRegisters
      83             :     /// ([crate::registers::BitOutputRegister], [crate::registers::FloatOutputRegister] and [crate::registers::ComplexOutputRegister]).  
      84             :     ///
      85             :     ///
      86             :     /// # Arguments
      87             :     ///
      88             :     /// * `circuit` - The iterator over operations that is run on the backend (corresponds to a circuit).
      89             :     ///
      90             :     /// # Returns
      91             :     ///
      92             :     /// `RegisterResult` - The output registers written by the evaluated circuits.
      93             :     fn run_circuit_iterator<'a>(
      94             :         &self,
      95             :         circuit: impl Iterator<Item = &'a Operation>,
      96             :     ) -> RegisterResult;
      97             : 
      98             :     /// Runs all circuits corresponding to one measurement with the backend.
      99             :     ///
     100             :     /// An expectation value measurement in general involves several circuits.
     101             :     /// Each circuit is passes to the backend and executed separately.
     102             :     /// During execution values are written to and read from classical registers
     103             :     /// ([crate::registers::BitRegister], [crate::registers::FloatRegister] and [crate::registers::ComplexRegister]).
     104             :     /// To produce sufficient statistics for evaluating expectationg values,
     105             :     /// circuits have to be run multiple times.
     106             :     /// The results of each repetition are concatenated in OutputRegisters
     107             :     /// ([crate::registers::BitOutputRegister], [crate::registers::FloatOutputRegister] and [crate::registers::ComplexOutputRegister]).  
     108             :     /// At the end all OutputRegisters are combined in a single HashMap for each type of register.
     109             :     ///
     110             :     /// # Arguments
     111             :     ///
     112             :     /// * `measurement` - The measurement that is run on the backend.
     113             :     ///
     114             :     /// # Returns
     115             :     ///
     116             :     /// `RegisterResult` - The output registers written by the evaluated measurement circuits.
     117           4 :     fn run_measurement_registers<T>(&self, measurement: &T) -> RegisterResult
     118           4 :     where
     119           4 :         T: Measure,
     120           4 :     {
     121           4 :         let mut bit_registers: HashMap<String, BitOutputRegister> = HashMap::new();
     122           4 :         let mut float_registers: HashMap<String, FloatOutputRegister> = HashMap::new();
     123           4 :         let mut complex_registers: HashMap<String, ComplexOutputRegister> = HashMap::new();
     124             : 
     125           4 :         for circuit in measurement.circuits() {
     126           4 :             let (tmp_bit_reg, tmp_float_reg, tmp_complex_reg) = match measurement.constant_circuit()
     127             :             {
     128           4 :                 Some(x) => self.run_circuit_iterator(x.iter().chain(circuit.iter()))?,
     129           0 :                 None => self.run_circuit_iterator(circuit.iter())?,
     130             :             };
     131             : 
     132           4 :             for (key, mut val) in tmp_bit_reg.into_iter() {
     133           0 :                 if let Some(x) = bit_registers.get_mut(&key) {
     134           0 :                     x.append(&mut val);
     135           0 :                 } else {
     136           0 :                     let _ = bit_registers.insert(key, val);
     137           0 :                 }
     138             :             }
     139           4 :             for (key, mut val) in tmp_float_reg.into_iter() {
     140           0 :                 if let Some(x) = float_registers.get_mut(&key) {
     141           0 :                     x.append(&mut val);
     142           0 :                 } else {
     143           0 :                     let _ = float_registers.insert(key, val);
     144           0 :                 }
     145             :             }
     146           4 :             for (key, mut val) in tmp_complex_reg.into_iter() {
     147           0 :                 if let Some(x) = complex_registers.get_mut(&key) {
     148           0 :                     x.append(&mut val);
     149           0 :                 } else {
     150           0 :                     let _ = complex_registers.insert(key, val);
     151           0 :                 }
     152             :             }
     153             :         }
     154           4 :         Ok((bit_registers, float_registers, complex_registers))
     155           4 :     }
     156             :     /// Evaluates expectation values of a measurement with the backend.
     157             :     ///
     158             :     /// # Arguments
     159             :     ///
     160             :     /// * `measurement` - The measurement that is run on the backend.
     161             :     ///
     162             :     /// # Returns
     163             :     ///
     164             :     /// `Ok(Option<HashMap<String, f64>>)` - The HashMap of measurement results.
     165             :     /// `Err(RoqoqoBackendError)` - The measurement run failed.
     166           3 :     fn run_measurement<T>(
     167           3 :         &self,
     168           3 :         measurement: &T,
     169           3 :     ) -> Result<Option<HashMap<String, f64>>, RoqoqoBackendError>
     170           3 :     where
     171           3 :         T: MeasureExpectationValues,
     172           3 :     {
     173           3 :         let (bit_registers, float_registers, complex_registers) =
     174           3 :             self.run_measurement_registers(measurement)?;
     175           3 :         Ok(measurement.evaluate(bit_registers, float_registers, complex_registers)?)
     176           3 :     }
     177             : }

Generated by: LCOV version 1.13