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