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 std::collections::HashMap;
14 :
15 : use crate::backends::{EvaluatingBackend, RegisterResult};
16 : use crate::measurements;
17 : use crate::measurements::Measure;
18 : use crate::RoqoqoBackendError;
19 : use std::fmt::{Display, Formatter};
20 : /// Represents a quantum program evaluating measurements based on a one or more free float parameters.
21 : ///
22 : /// The main use of QuantumProgram is to contain a Measurements implementing [crate::measurements::Measure]
23 : /// that measures expectation values or output registers of [crate::Circuit] quantum circuits that contain
24 : /// symbolic parameters. Circuit with symbolic parameters can not be simulated or executed on real hardware.
25 : /// The symbolic parameters need to be replaced with real floating point numbers first.
26 : /// A QuantumProgram contains a list of the free parameters (`input_parameter_names`) and can automatically
27 : /// replace the parameters with its `run` methods and return the result.
28 : ///
29 : /// The QuantumProgram should correspond as closely as possible to a normal mulit-parameter function
30 : /// in classical computing that can be called with a set of parameters and returns a result.
31 : /// It is the intended way to interface between normal program code and roqoqo based quantum programs.
32 : ///
33 : #[derive(Debug, PartialEq, Clone)]
34 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
35 : pub enum QuantumProgram {
36 : /// Variant for basis rotation measurement based quantum programs
37 : BasisRotation {
38 : /// The measurement that is performed
39 : measurement: measurements::BasisRotation,
40 : /// List of free input parameters that can be set when the QuantumProgram is executed
41 : input_parameter_names: Vec<String>,
42 : },
43 : /// Variant for cheated basis rotation measurement based quantum programs
44 : CheatedBasisRotation {
45 : /// The measurement that is performed
46 : measurement: measurements::CheatedBasisRotation,
47 : /// List of free input parameters that can be set when the QuantumProgram is executed
48 : input_parameter_names: Vec<String>,
49 : },
50 : /// Variant for statevector/density matrix based measurements
51 : Cheated {
52 : /// The measurement that is performed
53 : measurement: measurements::Cheated,
54 : /// List of free input parameters that can be set when the QuantumProgram is executed
55 : input_parameter_names: Vec<String>,
56 : },
57 : /// Variant quantum programs returning full classical registers
58 : ClassicalRegister {
59 : /// The measurement that is performed
60 : measurement: measurements::ClassicalRegister,
61 : /// List of free input parameters that can be set when the QuantumProgram is executed
62 : input_parameter_names: Vec<String>,
63 : },
64 : }
65 :
66 : impl QuantumProgram {
67 : /// Runs the QuantumProgram and returns expectation values.
68 : ///
69 : /// Runs the quantum programm for a given set of parameters passed in the same order as the parameters
70 : /// listed in `input_parameter_names` and returns expectation values.
71 : ///
72 : /// Arguments:
73 : ///
74 : /// * `backend` - The backend the program is executed on.
75 : /// * `parameters` - List of float ([f64]) parameters of the function call in order of `input_parameter_names`
76 10 : pub fn run<T>(
77 10 : &self,
78 10 : backend: T,
79 10 : parameters: &[f64],
80 10 : ) -> Result<Option<HashMap<String, f64>>, RoqoqoBackendError>
81 10 : where
82 10 : T: EvaluatingBackend,
83 10 : {
84 10 : match self{
85 3 : QuantumProgram::BasisRotation{measurement, input_parameter_names } => {
86 3 : if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
87 2 : let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
88 1 : let substituted_measurement = measurement.substitute_parameters(
89 1 : substituted_parameters
90 1 : )?;
91 1 : backend.run_measurement(&substituted_measurement)
92 : }
93 3 : QuantumProgram::CheatedBasisRotation{measurement, input_parameter_names } => {
94 3 : if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
95 2 : let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
96 1 : let substituted_measurement = measurement.substitute_parameters(
97 1 : substituted_parameters
98 1 : )?;
99 1 : backend.run_measurement(&substituted_measurement)
100 : }
101 3 : QuantumProgram::Cheated{measurement, input_parameter_names } => {
102 3 : if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
103 2 : let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
104 1 : let substituted_measurement = measurement.substitute_parameters(
105 1 : substituted_parameters
106 1 : )?;
107 1 : backend.run_measurement(&substituted_measurement)
108 : }
109 1 : _ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning classical registeres cannot be executed by `run` use `run_registers` instead".to_string()})
110 : }
111 10 : }
112 :
113 : /// Runs the QuantumProgram and returns the classical registers of the quantum program.
114 : ///
115 : /// Runs the quantum programm for a given set of parameters passed in the same order as the parameters
116 : /// listed in `input_parameter_names` and returns the classical register output.
117 : /// The classical registers usually contain a record of measurement values for the repeated execution
118 : /// of a [crate::Circuit] quantum circuit for real quantum hardware
119 : /// or the readout of the statevector or the density matrix for simulators.
120 : ///
121 : /// Arguments:
122 : ///
123 : /// * `backend` - The backend the program is executed on.
124 : /// * `parameters` - List of float ([f64]) parameters of the function call in order of `input_parameter_names`
125 6 : pub fn run_registers<T>(&self, backend: T, parameters: &[f64]) -> RegisterResult
126 6 : where
127 6 : T: EvaluatingBackend,
128 6 : {
129 6 : match self{
130 3 : QuantumProgram::ClassicalRegister{measurement, input_parameter_names } => {
131 3 : if parameters.len() != input_parameter_names.len() { return Err(RoqoqoBackendError::GenericError{msg: format!("Wrong number of parameters {} parameters expected {} parameters given", input_parameter_names.len(), parameters.len())})};
132 2 : let substituted_parameters: HashMap<String, f64> = input_parameter_names.iter().zip(parameters.iter()).map(|(key, value)| (key.clone(), *value)).collect();
133 1 : let substituted_measurement = measurement.substitute_parameters(
134 1 : substituted_parameters
135 1 : )?;
136 1 : backend.run_measurement_registers(&substituted_measurement)
137 : }
138 3 : _ => Err(RoqoqoBackendError::GenericError{msg: "A quantum programm returning expectation values cannot be executed by `run_registers` use `run` instead".to_string()})
139 : }
140 6 : }
141 : }
142 :
143 : /// Implements the Display trait for QuantumProgram.
144 : impl Display for QuantumProgram {
145 : fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
146 : let mut s: String = String::new();
147 :
148 : match self {
149 : QuantumProgram::BasisRotation { .. } => {
150 : s.push_str(&"QuantumProgram::BasisRotation".to_string());
151 : }
152 : QuantumProgram::CheatedBasisRotation { .. } => {
153 : s.push_str(&"QuantumProgram::CheatedBasisRotation".to_string());
154 : }
155 : QuantumProgram::Cheated { .. } => {
156 : s.push_str(&"QuantumProgram::Cheated".to_string());
157 : }
158 : QuantumProgram::ClassicalRegister { .. } => {
159 : s.push_str(&"QuantumProgram::ClassicalRegister".to_string());
160 : }
161 : }
162 :
163 : write!(f, "{}", s)
164 : }
165 : }
|