LCOV - code coverage report
Current view: top level - src/measurements - cheated_measurement.rs (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 106 107 99.1 %
Date: 2021-11-09 13:25:48 Functions: 11 11 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::measurements::{CheatedInput, Measure, MeasureExpectationValues};
      14             : use crate::registers::{BitOutputRegister, ComplexOutputRegister, FloatOutputRegister};
      15             : use crate::Circuit;
      16             : use crate::RoqoqoError;
      17             : use ndarray::{Array1, ArrayView1, ArrayView2};
      18             : //use ndarray::{Array2};
      19             : use num_complex::Complex64;
      20             : //use sprs::{CsMat, TriMat};
      21             : use std::collections::HashMap;
      22             : 
      23             : /// Cheated measurement using state obtained from simulator backend.
      24             : ///
      25             : /// Cheated measurements are only possible witch simulator backends that can return the state vector or the density matrix of the quantum computer.
      26             : /// The expectation values are defined by a matrix representation of the measured observables.
      27           2 : #[derive(Debug, PartialEq, Clone)]
      28             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
      29             : pub struct Cheated {
      30             :     /// Constant Circuit that is executed before each Circuit in circuits.
      31             :     pub constant_circuit: Option<Circuit>,
      32             :     /// Collection of quantum circuits for the separate basis rotations.
      33             :     pub circuits: Vec<Circuit>,
      34             :     /// Additional input information required for measurement.
      35             :     pub input: CheatedInput,
      36             : }
      37             : 
      38             : impl Measure for Cheated {
      39             :     /// Returns the constant Circuit that is executed before each Circuit in circuits.
      40             :     ///
      41             :     /// # Returns
      42             :     ///
      43             :     /// * `&Option<Circuit` - The constant Circuit (None if not defined).
      44           3 :     fn constant_circuit(&self) -> &Option<Circuit> {
      45           3 :         &self.constant_circuit
      46           3 :     }
      47             : 
      48             :     /// Returns iterator over circuits for measurement.
      49             :     ///
      50             :     /// # Returns
      51             :     ///
      52             :     /// * `Box<dyn Iterator<Item = &'a Circuit> + 'a>` - The quantum circuits.
      53           3 :     fn circuits<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Circuit> + 'a> {
      54           3 :         Box::new(self.circuits.iter())
      55           3 :     }
      56             : 
      57             :     /// Returns clone of Measurement with symbolic parameters replaced.
      58             :     ///
      59             :     /// # Arguments
      60             :     ///
      61             :     /// * `substituted_parameters` - The HashMap containing the substitutions to use in the Circuit.
      62             :     ///
      63             :     /// # Returns
      64             :     ///
      65             :     /// * `Ok(Self)` -  The Circuits with the parameters substituted.
      66             :     /// * `Err(RoqoqoError)` - The subsitution failed.
      67           3 :     fn substitute_parameters(
      68           3 :         &self,
      69           3 :         substituted_parameters: HashMap<String, f64>,
      70           3 :     ) -> Result<Self, RoqoqoError> {
      71           3 :         let mut calculator = qoqo_calculator::Calculator::new();
      72           9 :         for (name, val) in substituted_parameters.iter() {
      73           6 :             calculator.set_variable(name, *val)
      74             :         }
      75           3 :         let new_constant_circuit = match &self.constant_circuit {
      76           0 :             None => None,
      77           3 :             Some(c) => Some(c.substitute_parameters(&mut calculator)?),
      78             :         };
      79           2 :         let mut new_circuits = Vec::new();
      80           2 :         for circ in self.circuits.iter() {
      81           2 :             let mut calculator = qoqo_calculator::Calculator::new();
      82           6 :             for (name, val) in substituted_parameters.iter() {
      83           4 :                 calculator.set_variable(name, *val)
      84             :             }
      85           2 :             new_circuits.push(circ.substitute_parameters(&mut calculator)?)
      86             :         }
      87           2 :         Ok(Self {
      88           2 :             constant_circuit: new_constant_circuit,
      89           2 :             circuits: new_circuits,
      90           2 :             input: self.input.clone(),
      91           2 :         })
      92           3 :     }
      93             : }
      94             : 
      95             : impl MeasureExpectationValues for Cheated {
      96             :     /// Executes the cheated measurement.
      97             :     ///
      98             :     /// # Arguments
      99             :     ///
     100             :     /// * `bit_registers` - The classical bit registers as a HashMap with the register name as key.
     101             :     /// * `float_registers` - The classical float registers as a HashMap with the register name as key.
     102             :     /// * `complex_registers` - The classical complex registers as a HashMap with the register name as key.
     103             :     ///
     104             :     /// # Returns
     105             :     ///
     106             :     /// * `Ok(Some(HashMap<String, f64>))` - The measurement has been evaluated successfully. The HashMap contains the measured expectation values.
     107             :     /// * `Ok(None)` - The measurement did not fail but is incomplete. A new round of measurements is needed.
     108             :     /// * `Err([RoqoqoError::MissingRegister])` - The OutputRegister is missing.
     109             :     /// * `Err([RoqoqoError::MismatchedRegisterDimension])` - The dimension of register exceeds Hilbert space dimension of qubits.
     110             :     #[allow(unused_variables)]
     111           9 :     fn evaluate(
     112           9 :         &self,
     113           9 :         bit_registers: HashMap<String, BitOutputRegister>,
     114           9 :         float_registers: HashMap<String, FloatOutputRegister>,
     115           9 :         complex_registers: HashMap<String, ComplexOutputRegister>,
     116           9 :     ) -> Result<Option<HashMap<String, f64>>, RoqoqoError> {
     117           9 :         let dimension = 2_usize.pow(self.input.number_qubits as u32);
     118           9 :         // Evaluating expectation values
     119           9 :         let mut results: HashMap<String, f64> = HashMap::new();
     120          21 :         for (name, (operator, readout)) in self.input.measured_operators.iter() {
     121             :             // let row_inds: Vec<usize> = operator.iter().map(|(row, _, _)| row).cloned().collect();
     122             :             // let col_inds: Vec<usize> = operator.iter().map(|(_, col, _)| col).cloned().collect();
     123             :             // let data: Vec<Complex64> = operator.iter().map(|(_, _, val)| val).cloned().collect();
     124             :             // let tmp_tri = TriMat::from_triplets((dimension, dimension), row_inds, col_inds, data);
     125             :             // let matrix: CsMat<Complex64> = tmp_tri.to_csc();
     126          13 :             let register_vec =
     127          14 :                 complex_registers
     128          14 :                     .get(readout)
     129          14 :                     .ok_or_else(|| RoqoqoError::MissingRegister {
     130           1 :                         name: readout.clone(),
     131          14 :                     })?;
     132          13 :             let mut local_results: Array1<f64> = Array1::zeros(register_vec.len());
     133          17 :             for (index, register) in register_vec.iter().enumerate() {
     134          17 :                 if register.len() == dimension {
     135          12 :                     let vector: ArrayView1<Complex64> = ArrayView1::<Complex64>::from(register);
     136          12 :                     // let complex_conj_vec: Vec<Complex64> =
     137          12 :                     //     register.iter().map(|x| x.conj()).collect();
     138          12 :                     // let complex_conj: ArrayView1<Complex64> =
     139          12 :                     //     ArrayView1::<Complex64>::from(&complex_conj_vec);
     140          12 :                     // let tmp_val: Complex64 = complex_conj.dot(&(&matrix * &vector));
     141          12 :                     let tmp_val: Complex64 =
     142          12 :                         sparse_matrix_vector_expectation_value(operator, &vector);
     143          12 :                     local_results[index] = tmp_val.re;
     144          12 :                 } else if register.len() == dimension * dimension {
     145           4 :                     let vector: ArrayView2<Complex64> =
     146           4 :                         ArrayView2::<Complex64>::from_shape((dimension, dimension), register)
     147           4 :                             .expect("Unexpected error reshaping array");
     148           4 :                     // let complex_conj_vec: Vec<Complex64> =
     149           4 :                     //     register.iter().map(|x| x.conj()).collect();
     150           4 :                     // let complex_conj: Array2<Complex64> = Array2::<Complex64>::from_shape_vec(
     151           4 :                     //     (dimension, dimension),
     152           4 :                     //     complex_conj_vec,
     153           4 :                     // )
     154           4 :                     // .expect("Unexpected error reshaping array");
     155           4 :                     // let tmp_val: Complex64 =
     156           4 :                     //     ((complex_conj.t()).dot(&(&matrix * &vector))).diag().sum();
     157           4 :                     let tmp_val =
     158           4 :                         sparse_matrix_matrix_expectation_value(operator, &vector, dimension);
     159           4 :                     local_results[index] = tmp_val.re;
     160           4 :                 } else {
     161           1 :                     return Err(RoqoqoError::MismatchedRegisterDimension {
     162           1 :                         dim: register.len(),
     163           1 :                         number_qubits: self.input.number_qubits,
     164           1 :                     });
     165             :                 }
     166             :             }
     167             : 
     168          12 :             results.insert(
     169          12 :                 name.clone(),
     170          12 :                 local_results.mean().expect(
     171          12 :                     "Unexpectedly could not calculate mean of expectation values of register",
     172          12 :                 ),
     173          12 :             );
     174             :         }
     175           7 :         Ok(Some(results))
     176           9 :     }
     177             : }
     178             : 
     179             : #[inline]
     180          12 : fn sparse_matrix_vector_expectation_value(
     181          12 :     matrix: &[(usize, usize, Complex64)],
     182          12 :     vector: &ArrayView1<Complex64>,
     183          12 : ) -> Complex64 {
     184          12 :     let mut val: Complex64 = Complex64::new(0.0, 0.0);
     185          60 :     for (index_i, index_j, value) in matrix {
     186          48 :         val += vector[*index_i].conj() * value * vector[*index_j]
     187             :     }
     188          12 :     val
     189          12 : }
     190             : 
     191             : #[inline]
     192           4 : fn sparse_matrix_matrix_expectation_value(
     193           4 :     matrix: &[(usize, usize, Complex64)],
     194           4 :     dense_matrix: &ArrayView2<Complex64>,
     195           4 :     dimension: usize,
     196           4 : ) -> Complex64 {
     197           4 :     let mut val: Complex64 = Complex64::new(0.0, 0.0);
     198          20 :     for (index_j, index_k, value) in matrix {
     199          32 :         for index_i in 0..dimension {
     200          32 :             val +=
     201          32 :                 dense_matrix[(*index_j, index_i)].conj() * value * dense_matrix[(*index_k, index_i)]
     202             :         }
     203             :     }
     204           4 :     val
     205           4 : }

Generated by: LCOV version 1.13