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