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 super::*;
14 : use ndarray::Array1;
15 : #[cfg(feature = "serialize")]
16 : use serde::{Deserialize, Serialize};
17 :
18 : /// Collected information for executing a cheated basis rotation measurement.
19 2 : #[derive(Debug, PartialEq, Clone)]
20 : #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
21 : pub struct CheatedBasisRotation {
22 : /// Constant Circuit that is executed before each Circuit in circuits.
23 : pub constant_circuit: Option<Circuit>,
24 : /// Collection of quantum circuits for the separate basis rotations.
25 : pub circuits: Vec<Circuit>,
26 : /// Additional input information required for measurement.
27 : pub input: CheatedBasisRotationInput,
28 : }
29 :
30 : impl Measure for CheatedBasisRotation {
31 : /// Returns the constant Circuit that is executed before each Circuit in circuits.
32 : ///
33 : /// # Returns
34 : ///
35 : /// * `&Option<Circuit` - The constant Circuit (None if not defined).
36 3 : fn constant_circuit(&self) -> &Option<Circuit> {
37 3 : &self.constant_circuit
38 3 : }
39 :
40 : /// Returns iterator over circuits for measurement.
41 : ///
42 : /// # Returns
43 : ///
44 : /// * `Box<dyn Iterator<Item = &'a Circuit> + 'a>` - The quantum circuits.
45 3 : fn circuits<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Circuit> + 'a> {
46 3 : Box::new(self.circuits.iter())
47 3 : }
48 :
49 : /// Returns clone of Measurement with symbolic parameters replaced.
50 : ///
51 : /// # Arguments
52 : ///
53 : /// * `substituted_parameters` - The HashMap containing the substitutions to use in the Circuit.
54 : ///
55 : /// # Returns
56 : ///
57 : /// * `Ok(Self)` - The Circuits with the parameters substituted.
58 : /// * `Err(RoqoqoError)` - The subsitution failed.
59 3 : fn substitute_parameters(
60 3 : &self,
61 3 : substituted_parameters: HashMap<String, f64>,
62 3 : ) -> Result<Self, RoqoqoError> {
63 3 : let mut calculator = qoqo_calculator::Calculator::new();
64 9 : for (name, val) in substituted_parameters.iter() {
65 6 : calculator.set_variable(name, *val)
66 : }
67 3 : let new_constant_circuit = match &self.constant_circuit {
68 0 : None => None,
69 3 : Some(c) => Some(c.substitute_parameters(&mut calculator)?),
70 : };
71 2 : let mut new_circuits = Vec::new();
72 2 : for circ in self.circuits.iter() {
73 2 : let mut calculator = qoqo_calculator::Calculator::new();
74 6 : for (name, val) in substituted_parameters.iter() {
75 4 : calculator.set_variable(name, *val)
76 : }
77 2 : new_circuits.push(circ.substitute_parameters(&mut calculator)?)
78 : }
79 2 : Ok(Self {
80 2 : constant_circuit: new_constant_circuit,
81 2 : circuits: new_circuits,
82 2 : input: self.input.clone(),
83 2 : })
84 3 : }
85 : }
86 :
87 : impl MeasureExpectationValues for CheatedBasisRotation {
88 : /// Executes the cheated basis rotation measurement
89 : ///
90 : /// # Arguments
91 : ///
92 : /// * `bit_registers` - The classical bit registers as a HashMap with the register name as key
93 : /// * `float_registers` - The classical float registers as a HashMap with the register name as key
94 : /// * `complex_registers` - The classical complex registers as a HashMap with the register name as key
95 : ///
96 : /// # Returns
97 : ///
98 : /// * `Ok(Some(HashMap<String, f64>))` - The measurement has been evaluated successfully. The HashMap contains the measured expectation values
99 : /// * `Ok(None)` - The measurement did not fail but is incomplete. A new round of measurements is needed
100 : /// * `Err(RoqoqoError)` - Calculator parsing error.
101 : ///
102 : #[allow(unused_variables)]
103 3 : fn evaluate(
104 3 : &self,
105 3 : bit_registers: HashMap<String, BitOutputRegister>,
106 3 : float_registers: HashMap<String, FloatOutputRegister>,
107 3 : complex_registers: HashMap<String, ComplexOutputRegister>,
108 3 : ) -> Result<Option<HashMap<String, f64>>, RoqoqoError> {
109 3 : let mut pauli_products: Array1<f64> = Array1::zeros(self.input.pauli_product_keys.len());
110 9 : for (register_name, register) in float_registers.iter() {
111 6 : if let Some(index) = self.input.pauli_product_keys.get(register_name) {
112 6 : pauli_products[*index] = register[0][0];
113 6 : }
114 : }
115 : // Evaluating expectation values
116 3 : let mut results: HashMap<String, f64> = HashMap::new();
117 :
118 6 : for (name, evaluation) in self.input.measured_exp_vals.iter() {
119 : results.insert(
120 3 : name.clone(),
121 3 : match evaluation {
122 2 : PauliProductsToExpVal::Linear(hm) => {
123 2 : let mut value: f64 = 0.0;
124 6 : for (index, coefficient) in hm {
125 4 : value += pauli_products[*index] * coefficient;
126 4 : }
127 2 : value
128 : }
129 1 : PauliProductsToExpVal::Symbolic(x) => {
130 1 : let mut calculator = qoqo_calculator::Calculator::new();
131 3 : for (ind, p) in pauli_products.iter().enumerate() {
132 3 : dbg!(ind);
133 3 : dbg!(p);
134 3 : calculator.set_variable(format!("pauli_product_{}", ind).as_str(), *p);
135 3 : }
136 1 : calculator.parse_get(x.clone())?
137 : }
138 : },
139 : );
140 : }
141 :
142 3 : Ok(Some(results))
143 3 : }
144 : }
|