roqoqo_aqt/interface.rs
1// Copyright © 2021-2024 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
13use roqoqo::operations::*;
14use roqoqo::Circuit;
15use roqoqo::RoqoqoBackendError;
16
17// Pragma operations that are ignored by backend and do not throw an error
18const ALLOWED_OPERATIONS: &[&str; 12] = &[
19 "PragmaSetNumberOfMeasurements",
20 "PragmaBoostNoise",
21 "PragmaStopParallelBlock",
22 "PragmaGlobalPhase",
23 "DefinitionBit",
24 "DefinitionFloat",
25 "DefinitionComplex",
26 "InputSymbolic",
27 "InputBit",
28 "PragmaRepeatedMeasurement",
29 "PragmaStartDecompositionBlock",
30 "PragmaStopDecompositionBlock",
31 // "PragmaLoop", // CHECK
32 // "PhaseShiftedControlledPhase", // CHECK
33];
34
35/// Representation for AQT backend instructions serialized to Json
36#[derive(PartialEq, Debug, Clone, serde::Serialize, serde::Deserialize)]
37#[serde(tag = "operation")]
38pub enum AqtInstruction {
39 /// Instruction involving RZ gate
40 RZ {
41 /// angle of rotation in PI radians [0 - 2]
42 phi: f64,
43 /// qubit where gate is applied
44 qubit: u32,
45 },
46 /// Instruction involving R gate
47 R {
48 /// polar angle of rotation in PI radians [0 - 1]
49 phi: f64,
50 /// radial angle of rotation in PI radians [0 - 2]
51 theta: f64,
52 /// qubit where gate is applied
53 qubit: u32,
54 },
55 /// Instruction involving MolmerSorensenXX gate
56 RXX {
57 /// qubits where gate is applied
58 qubits: Vec<u32>,
59 /// angle of rotation in PI radians [0 - 2]
60 theta: f64,
61 },
62 /// Instruction to measure all qubits
63 MEASURE,
64}
65
66/// Converts all operations in a [roqoqo::Circuit] into instructions for AQT Hardware or AQT Simulators
67///
68/// # Arguments
69///
70/// `circuit` - The [roqoqo::Circuit] that is converted
71///
72/// # Returns
73///
74/// `Vec<AqtInstruction>` - List of converted instructions
75/// `RoqoqoBackendError::OperationNotInBackend` - Error when [roqoqo::operations::Operation] can not be converted
76pub fn call_circuit(circuit: &Circuit) -> Result<Vec<AqtInstruction>, RoqoqoBackendError> {
77 let mut circuit_vec: Vec<AqtInstruction> = Vec::new();
78 for op in circuit.iter() {
79 if let Some(instruction) = call_operation(op)? {
80 circuit_vec.push(instruction);
81 }
82 }
83 Ok(circuit_vec)
84}
85
86/// Converts a [roqoqo::operations::Operation] into an instruction for AQT Hardware or AQT Simulators.
87/// *Note* - Any measurment operation, regardless of the specific qubits defined, will always measure all the qubits.
88///
89/// # Arguments
90///
91/// `operation` - The [roqoqo::operations::Operation] that is converted
92///
93/// # Returns
94///
95/// `AqtInstruction` - Converted instruction
96/// `RoqoqoBackendError::OperationNotInBackend` - Error when [roqoqo::operations::Operation] can not be converted
97pub fn call_operation(operation: &Operation) -> Result<Option<AqtInstruction>, RoqoqoBackendError> {
98 match operation {
99 Operation::RotateZ(op) => Ok(Some(AqtInstruction::RZ {
100 phi: *op.theta().float()? / std::f64::consts::PI,
101 qubit: *op.qubit() as u32,
102 })),
103 Operation::RotateX(op) => Ok(Some(AqtInstruction::R {
104 phi: 0.0,
105 theta: *op.theta().float()? / std::f64::consts::PI,
106 qubit: *op.qubit() as u32,
107 })),
108 Operation::RotateY(op) => Ok(Some(AqtInstruction::R {
109 phi: 0.5,
110 theta: *op.theta().float()? / std::f64::consts::PI,
111 qubit: *op.qubit() as u32,
112 })),
113 Operation::PauliZ(op) => Ok(Some(AqtInstruction::RZ {
114 phi: 1.0,
115 qubit: *op.qubit() as u32,
116 })),
117 Operation::PauliX(op) => Ok(Some(AqtInstruction::R {
118 phi: 0.0,
119 theta: 1.0,
120 qubit: *op.qubit() as u32,
121 })),
122 Operation::PauliY(op) => Ok(Some(AqtInstruction::R {
123 phi: 0.5,
124 theta: 1.0,
125 qubit: *op.qubit() as u32,
126 })),
127 // Variable MSXX is different in qoqo and aqt
128 Operation::VariableMSXX(op) => Ok(Some(AqtInstruction::RXX {
129 qubits: vec![*op.control() as u32, *op.target() as u32],
130 theta: *op.theta().float()? / 2.0,
131 })),
132 Operation::MolmerSorensenXX(op) => Ok(Some(AqtInstruction::RXX {
133 qubits: vec![*op.control() as u32, *op.target() as u32],
134 theta: 0.5,
135 })),
136 // AQT device
137 Operation::PragmaRepeatedMeasurement(_op) => Ok(Some(AqtInstruction::MEASURE)),
138 Operation::MeasureQubit(_op) => Ok(Some(AqtInstruction::MEASURE)),
139 _ => {
140 if ALLOWED_OPERATIONS.contains(&operation.hqslang()) {
141 Ok(None)
142 } else {
143 Err(RoqoqoBackendError::OperationNotInBackend {
144 backend: "AQT",
145 hqslang: operation.hqslang(),
146 })
147 }
148 }
149 }
150}