roqoqo_qryd/lib.rs
1// Copyright © 2021-2022 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
14#![deny(missing_docs)]
15#![warn(rustdoc::private_intra_doc_links)]
16#![warn(rustdoc::missing_crate_level_docs)]
17#![warn(rustdoc::missing_doc_code_examples)]
18#![warn(rustdoc::private_doc_tests)]
19#![deny(missing_debug_implementations)]
20
21//! # roqoqo-qryd
22//!
23//! The `roqoqo-qryd` rust crate implements [qoqo](https://github.com/HQSquantumsimulations/qoqo) support for quantum computers and quantum computer emulators of the [QRydDemo](https://thequantumlaend.de/qryddemo/) project.
24//!
25//! The QRydDemo project builds on Quantum computers using Rydberg atoms.
26//! qoqo is quantum computing toolkit by [HQS Quantum Simulations](https://quantumsimulations.de).
27//!
28//! The roqoqo-qryd package contains the following functionality:
29//!
30//! ### Interface to the current QRydDemo WebAPI
31//!
32//! At the moment QRydDemo WebAPI allows access to Quantum Hardware Emulators of different device topology. roqoqo-qryd supports interfacing with the corresponding [REST-API](https://api.qryddemo.itp3.uni-stuttgart.de/docs) with low level calls as well as a high-level backend to qoqo quantum programs. For this it provides the backend `APIBackend` to evaluate roqoqo quantum programs and the `api_devices` module to represent devices available on the emulators.
33//!
34//! ### QRydDemo specific hardware operations (prototype)
35//!
36//! Rydberg atom based quantum devices support, in principle, operations not commonly found in other quantum hardware. Changes in device topology are one of these operations. roqoqo-qryd adds support for changes in device topology to roqoqo via the operations in its `pragma_operations` module.
37//! Note that this is a preview prototype and does not represent a finalized set of operations on the QRydDemo hardware.
38//!
39//! ### Local simulator supporting specific hardware operations
40//!
41//! roqoqo-qryd includes a local [QuEST](https://github.com/QuEST-Kit/QuEST) based simulator for quantum devices supporting the Rydberg specific quantum operations. The simulator is intended to let users test the capabilities of quantum hardware with the additional operations.
42//! roqoqo-qryd provides the simulator via the `SimulatorBackend` backend the implements the roqoqo `Backend` trait.The backend uses the device prototypes in roqoqo-qryd's `qryd_devices` module.
43//! Note that the devices for the simulator do not represent a finalised design for QRydDemo.
44
45/// Devices representing QRyd quantum computer(s)
46pub mod qryd_devices;
47pub use qryd_devices::*;
48
49/// Tweezer devices representing QRyd quantum computer(s)
50pub mod tweezer_devices;
51pub use tweezer_devices::*;
52
53/// Devices representing QRyd quantum computer(s)
54pub mod api_devices;
55pub use api_devices::*;
56
57/// QRyd specific PragmaOperations that support changing the QRyd device during a circuit evaluation
58pub mod pragma_operations;
59pub use pragma_operations::*;
60
61/// Emulator device, TweezerDevice instance with all-to-all connectivity
62pub mod emulator_devices;
63pub use emulator_devices::*;
64
65/// Simulator backend for the QRyd quantum computer
66#[cfg(feature = "simulator")]
67mod simulator_backend;
68#[cfg(feature = "simulator")]
69pub use simulator_backend::*;
70
71/// WebAPI backend for the QRyd quantum computer(s)
72#[cfg(feature = "web-api")]
73pub mod api_backend;
74#[cfg(feature = "web-api")]
75pub use api_backend::*;
76
77#[cfg(feature = "web-api")]
78use roqoqo::RoqoqoBackendError;
79#[cfg(feature = "web-api")]
80use std::env;
81
82/// Compute the angle according to the appropriate relation and phi/theta values.
83///
84/// # Arguments
85///
86/// `relation_name` - The name of the relation to refer to.
87/// `theta` - The theta angle to check.
88///
89/// # Returns
90///
91/// `Some<f64>` - The phi-theta relation.
92/// 'None' - The relation does not exist.
93///
94pub fn phi_theta_relation(relation_name: &str, mut theta: f64) -> Option<f64> {
95 while theta < 0.0 {
96 theta += 2.0 * std::f64::consts::PI;
97 }
98 while theta > 2.0 * std::f64::consts::PI {
99 theta -= 2.0 * std::f64::consts::PI
100 }
101 match relation_name {
102 "DefaultRelation" => Some(
103 5.11382
104 - 0.32933
105 * f64::ln(1.63085 * theta * theta * f64::exp(2.0 * theta) + theta + 0.02889),
106 ),
107 _ => None,
108 }
109}
110
111/// Enum for a Device that can be a TweezerDevice or an EmulatorDevice.
112#[derive(Debug)]
113pub enum CombinedDevice {
114 /// Variant for Tweezer devices
115 Tweezer(TweezerDevice),
116 /// Variant for Emulator devices
117 Emulator(EmulatorDevice),
118}
119
120/// Creates a new TweezerDevice instance containing populated tweezer data or EmulatorDevice instance.
121///
122/// This requires a valid QRYD_API_TOKEN. Visit `https://thequantumlaend.de/get-access/` to get one.
123///
124/// # Arguments
125///
126/// * `device_name` - The name of the device to instantiate. Defaults to "qryd_emulator".
127/// * `access_token` - An access_token is required to access QRYD hardware and emulators.
128/// The access_token can either be given as an argument here
129/// or set via the environmental variable `$QRYD_API_TOKEN`.
130/// * `seed` - Optionally overwrite seed value from downloaded device instance.
131/// * `dev` - The boolean to set the dev header to.
132/// * `api_version` - The version of the QRYD API to use. Defaults to "v1_1".
133///
134/// # Returns
135///
136/// * `CombinedDevice` - The new CombinedDevice instance, with variant TweezerDevice or
137/// EmulatorDevice depending on the pulled information.
138///
139/// # Errors
140///
141/// * `RoqoqoBackendError`
142#[cfg(feature = "web-api")]
143pub fn device_from_api(
144 device_name: Option<String>,
145 access_token: Option<String>,
146 seed: Option<usize>,
147 dev: Option<bool>,
148 api_version: Option<String>,
149) -> Result<CombinedDevice, RoqoqoBackendError> {
150 // Preparing variables
151 let device_name_internal = device_name.unwrap_or_else(|| String::from("qryd_emulator"));
152 let api_version = api_version.unwrap_or_else(|| String::from("v1_1"));
153 let dev = dev.unwrap_or(false);
154 let hqs_env_var = env::var("QRYD_API_HQS").is_ok();
155 let access_token_internal: String = match access_token {
156 Some(s) => s,
157 None => {
158 env::var("QRYD_API_TOKEN").map_err(|_| RoqoqoBackendError::MissingAuthentication {
159 msg: "QRYD access token is missing.".to_string(),
160 })?
161 }
162 };
163
164 // Client setup
165 let client = reqwest::blocking::Client::builder()
166 .https_only(true)
167 .build()
168 .map_err(|x| RoqoqoBackendError::NetworkError {
169 msg: format!("Could not create https client {:?}.", x),
170 })?;
171
172 // Response gathering
173 let resp = match (dev, hqs_env_var) {
174 (true, true) => client
175 .get(format!(
176 "https://api.qryddemo.itp3.uni-stuttgart.de/{}/devices/{}",
177 api_version, device_name_internal
178 ))
179 .header("X-API-KEY", access_token_internal)
180 .header("X-DEV", "?1")
181 .header("X-HQS", "?1")
182 .send()
183 .map_err(|e| RoqoqoBackendError::NetworkError {
184 msg: format!("{:?}", e),
185 })?,
186 (true, false) => client
187 .get(format!(
188 "https://api.qryddemo.itp3.uni-stuttgart.de/{}/devices/{}",
189 api_version, device_name_internal
190 ))
191 .header("X-API-KEY", access_token_internal)
192 .header("X-DEV", "?1")
193 .send()
194 .map_err(|e| RoqoqoBackendError::NetworkError {
195 msg: format!("{:?}", e),
196 })?,
197 (false, true) => client
198 .get(format!(
199 "https://api.qryddemo.itp3.uni-stuttgart.de/{}/devices/{}",
200 api_version, device_name_internal
201 ))
202 .header("X-API-KEY", access_token_internal)
203 .header("X-HQS", "?1")
204 .send()
205 .map_err(|e| RoqoqoBackendError::NetworkError {
206 msg: format!("{:?}", e),
207 })?,
208 (false, false) => client
209 .get(format!(
210 "https://api.qryddemo.itp3.uni-stuttgart.de/{}/devices/{}",
211 api_version, device_name_internal
212 ))
213 .header("X-API-KEY", access_token_internal)
214 .send()
215 .map_err(|e| RoqoqoBackendError::NetworkError {
216 msg: format!("{:?}", e),
217 })?,
218 };
219
220 // Response handling
221 let status_code = resp.status();
222 if status_code == reqwest::StatusCode::OK {
223 if let Ok(mut device) = resp.json::<TweezerDevice>() {
224 if device.available_gates.is_some() {
225 if let Some(new_seed) = seed {
226 device.seed = Some(new_seed);
227 }
228 device.device_name = device_name_internal;
229 Ok(CombinedDevice::Emulator(EmulatorDevice {
230 internal: device,
231 }))
232 } else {
233 if let Some(default) = device.default_layout.clone() {
234 device.switch_layout(&default, None).unwrap();
235 }
236 if let Some(new_seed) = seed {
237 device.seed = Some(new_seed);
238 }
239 device.device_name = device_name_internal;
240 Ok(CombinedDevice::Tweezer(device))
241 }
242 } else {
243 Err(RoqoqoBackendError::GenericError {
244 msg: "Failed deserialization from device_from_api().".to_string(),
245 })
246 }
247 } else {
248 Err(RoqoqoBackendError::NetworkError {
249 msg: format!(
250 "Request to server failed with HTTP status code {:?}.",
251 status_code
252 ),
253 })
254 }
255}