microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.2.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc_eval/src/backend.rs

232lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use num_bigint::BigUint;
5use num_complex::Complex;
6use quantum_sparse_sim::QuantumSim;
7use rand::RngCore;
8
9use crate::val::Value;
10
11/// The trait that must be implemented by a quantum backend, whose functions will be invoked when
12/// quantum intrinsics are called.
13pub trait Backend {
14 type ResultType;
15
16 fn ccx(&mut self, ctl0: usize, ctl1: usize, q: usize);
17 fn cx(&mut self, ctl: usize, q: usize);
18 fn cy(&mut self, ctl: usize, q: usize);
19 fn cz(&mut self, ctl: usize, q: usize);
20 fn h(&mut self, q: usize);
21 fn m(&mut self, q: usize) -> Self::ResultType;
22 fn mresetz(&mut self, q: usize) -> Self::ResultType;
23 fn reset(&mut self, q: usize);
24 fn rx(&mut self, theta: f64, q: usize);
25 fn rxx(&mut self, theta: f64, q0: usize, q1: usize);
26 fn ry(&mut self, theta: f64, q: usize);
27 fn ryy(&mut self, theta: f64, q0: usize, q1: usize);
28 fn rz(&mut self, theta: f64, q: usize);
29 fn rzz(&mut self, theta: f64, q0: usize, q1: usize);
30 fn sadj(&mut self, q: usize);
31 fn s(&mut self, q: usize);
32 fn swap(&mut self, q0: usize, q1: usize);
33 fn tadj(&mut self, q: usize);
34 fn t(&mut self, q: usize);
35 fn x(&mut self, q: usize);
36 fn y(&mut self, q: usize);
37 fn z(&mut self, q: usize);
38 fn qubit_allocate(&mut self) -> usize;
39 fn qubit_release(&mut self, q: usize);
40 fn capture_quantum_state(&mut self) -> (Vec<(BigUint, Complex<f64>)>, usize);
41 fn qubit_is_zero(&mut self, q: usize) -> bool;
42
43 fn custom_intrinsic(&mut self, _name: &str, _arg: Value) -> Option<Result<Value, String>> {
44 None
45 }
46
47 fn set_seed(&mut self, _seed: Option<u64>) {}
48}
49
50/// Default backend used when targeting sparse simulation.
51pub struct SparseSim {
52 pub sim: QuantumSim,
53}
54
55impl Default for SparseSim {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl SparseSim {
62 #[must_use]
63 pub fn new() -> Self {
64 Self {
65 sim: QuantumSim::new(),
66 }
67 }
68}
69
70impl Backend for SparseSim {
71 type ResultType = bool;
72
73 fn ccx(&mut self, ctl0: usize, ctl1: usize, q: usize) {
74 self.sim.mcx(&[ctl0, ctl1], q);
75 }
76
77 fn cx(&mut self, ctl: usize, q: usize) {
78 self.sim.mcx(&[ctl], q);
79 }
80
81 fn cy(&mut self, ctl: usize, q: usize) {
82 self.sim.mcy(&[ctl], q);
83 }
84
85 fn cz(&mut self, ctl: usize, q: usize) {
86 self.sim.mcz(&[ctl], q);
87 }
88
89 fn h(&mut self, q: usize) {
90 self.sim.h(q);
91 }
92
93 fn m(&mut self, q: usize) -> Self::ResultType {
94 self.sim.measure(q)
95 }
96
97 fn mresetz(&mut self, q: usize) -> Self::ResultType {
98 let res = self.sim.measure(q);
99 if res {
100 self.sim.x(q);
101 }
102 res
103 }
104
105 fn reset(&mut self, q: usize) {
106 self.mresetz(q);
107 }
108
109 fn rx(&mut self, theta: f64, q: usize) {
110 self.sim.rx(theta, q);
111 }
112
113 fn rxx(&mut self, theta: f64, q0: usize, q1: usize) {
114 self.h(q0);
115 self.h(q1);
116 self.rzz(theta, q0, q1);
117 self.h(q1);
118 self.h(q0);
119 }
120
121 fn ry(&mut self, theta: f64, q: usize) {
122 self.sim.ry(theta, q);
123 }
124
125 fn ryy(&mut self, theta: f64, q0: usize, q1: usize) {
126 self.h(q0);
127 self.s(q0);
128 self.h(q0);
129 self.h(q1);
130 self.s(q1);
131 self.h(q1);
132 self.rzz(theta, q0, q1);
133 self.h(q1);
134 self.sadj(q1);
135 self.h(q1);
136 self.h(q0);
137 self.sadj(q0);
138 self.h(q0);
139 }
140
141 fn rz(&mut self, theta: f64, q: usize) {
142 self.sim.rz(theta, q);
143 }
144
145 fn rzz(&mut self, theta: f64, q0: usize, q1: usize) {
146 self.cx(q1, q0);
147 self.rz(theta, q0);
148 self.cx(q1, q0);
149 }
150
151 fn sadj(&mut self, q: usize) {
152 self.sim.sadj(q);
153 }
154
155 fn s(&mut self, q: usize) {
156 self.sim.s(q);
157 }
158
159 fn swap(&mut self, q0: usize, q1: usize) {
160 self.sim.swap_qubit_ids(q0, q1);
161 }
162
163 fn tadj(&mut self, q: usize) {
164 self.sim.tadj(q);
165 }
166
167 fn t(&mut self, q: usize) {
168 self.sim.t(q);
169 }
170
171 fn x(&mut self, q: usize) {
172 self.sim.x(q);
173 }
174
175 fn y(&mut self, q: usize) {
176 self.sim.y(q);
177 }
178
179 fn z(&mut self, q: usize) {
180 self.sim.z(q);
181 }
182
183 fn qubit_allocate(&mut self) -> usize {
184 self.sim.allocate()
185 }
186
187 fn qubit_release(&mut self, q: usize) {
188 self.sim.release(q);
189 }
190
191 fn capture_quantum_state(&mut self) -> (Vec<(BigUint, Complex<f64>)>, usize) {
192 let (state, count) = self.sim.get_state();
193 // Because the simulator returns the state indices with opposite endianness from the
194 // expected one, we need to reverse the bit order of the indices.
195 let mut new_state = state
196 .into_iter()
197 .map(|(idx, val)| {
198 let mut new_idx = BigUint::default();
199 for i in 0..(count as u64) {
200 if idx.bit((count as u64) - 1 - i) {
201 new_idx.set_bit(i, true);
202 }
203 }
204 (new_idx, val)
205 })
206 .collect::<Vec<_>>();
207 new_state.sort_unstable_by(|a, b| a.0.cmp(&b.0));
208 (new_state, count)
209 }
210
211 fn qubit_is_zero(&mut self, q: usize) -> bool {
212 self.sim.qubit_is_zero(q)
213 }
214
215 fn custom_intrinsic(&mut self, name: &str, _arg: Value) -> Option<Result<Value, String>> {
216 match name {
217 "BeginEstimateCaching" => Some(Ok(Value::Bool(true))),
218 "EndEstimateCaching"
219 | "AccountForEstimatesInternal"
220 | "BeginRepeatEstimatesInternal"
221 | "EndRepeatEstimatesInternal" => Some(Ok(Value::unit())),
222 _ => None,
223 }
224 }
225
226 fn set_seed(&mut self, seed: Option<u64>) {
227 match seed {
228 Some(seed) => self.sim.set_rng_seed(seed),
229 None => self.sim.set_rng_seed(rand::thread_rng().next_u64()),
230 }
231 }
232}
233