microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billt/revert-mimalloc

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_eval/src/intrinsic.rs

234lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4mod utils;
5
6#[cfg(test)]
7mod tests;
8
9use crate::{
10 backend::Backend,
11 error::PackageSpan,
12 output::Receiver,
13 val::{self, Qubit, Value},
14 Error,
15};
16use num_bigint::BigInt;
17use rand::{rngs::StdRng, Rng};
18use rustc_hash::FxHashSet;
19use std::array;
20
21#[allow(clippy::too_many_lines)]
22pub(crate) fn call(
23 name: &str,
24 name_span: PackageSpan,
25 arg: Value,
26 arg_span: PackageSpan,
27 sim: &mut dyn Backend<ResultType = impl Into<val::Result>>,
28 rng: &mut StdRng,
29 out: &mut dyn Receiver,
30) -> Result<Value, Error> {
31 match name {
32 "Length" => match arg.unwrap_array().len().try_into() {
33 Ok(len) => Ok(Value::Int(len)),
34 Err(_) => Err(Error::ArrayTooLarge(arg_span)),
35 },
36 #[allow(clippy::cast_precision_loss)]
37 "IntAsDouble" => Ok(Value::Double(arg.unwrap_int() as f64)),
38 "IntAsBigInt" => Ok(Value::BigInt(BigInt::from(arg.unwrap_int()))),
39 "DumpMachine" => {
40 let (state, qubit_count) = sim.capture_quantum_state();
41 match out.state(state, qubit_count) {
42 Ok(()) => Ok(Value::unit()),
43 Err(_) => Err(Error::OutputFail(name_span)),
44 }
45 }
46 "DumpRegister" => {
47 let qubits = arg.unwrap_array();
48 let qubits = qubits
49 .iter()
50 .map(|q| q.clone().unwrap_qubit().0)
51 .collect::<Vec<_>>();
52 if qubits.len() != qubits.iter().collect::<FxHashSet<_>>().len() {
53 return Err(Error::QubitUniqueness(arg_span));
54 }
55 let (state, qubit_count) = sim.capture_quantum_state();
56 let state = utils::split_state(&qubits, state, qubit_count)
57 .map_err(|()| Error::QubitsNotSeparable(arg_span))?;
58 match out.state(state, qubits.len()) {
59 Ok(()) => Ok(Value::unit()),
60 Err(_) => Err(Error::OutputFail(name_span)),
61 }
62 }
63 "Message" => match out.message(&arg.unwrap_string()) {
64 Ok(()) => Ok(Value::unit()),
65 Err(_) => Err(Error::OutputFail(name_span)),
66 },
67 "CheckZero" => Ok(Value::Bool(sim.qubit_is_zero(arg.unwrap_qubit().0))),
68 "ArcCos" => Ok(Value::Double(arg.unwrap_double().acos())),
69 "ArcSin" => Ok(Value::Double(arg.unwrap_double().asin())),
70 "ArcTan" => Ok(Value::Double(arg.unwrap_double().atan())),
71 "ArcTan2" => {
72 let [x, y] = unwrap_tuple(arg);
73 Ok(Value::Double(x.unwrap_double().atan2(y.unwrap_double())))
74 }
75 "Cos" => Ok(Value::Double(arg.unwrap_double().cos())),
76 "Cosh" => Ok(Value::Double(arg.unwrap_double().cosh())),
77 "Sin" => Ok(Value::Double(arg.unwrap_double().sin())),
78 "Sinh" => Ok(Value::Double(arg.unwrap_double().sinh())),
79 "Tan" => Ok(Value::Double(arg.unwrap_double().tan())),
80 "Tanh" => Ok(Value::Double(arg.unwrap_double().tanh())),
81 "Sqrt" => Ok(Value::Double(arg.unwrap_double().sqrt())),
82 "Log" => Ok(Value::Double(arg.unwrap_double().ln())),
83 "DrawRandomInt" => {
84 let [lo, hi] = unwrap_tuple(arg);
85 let lo = lo.unwrap_int();
86 let hi = hi.unwrap_int();
87 if lo > hi {
88 Err(Error::EmptyRange(arg_span))
89 } else {
90 Ok(Value::Int(rng.gen_range(lo..=hi)))
91 }
92 }
93 "DrawRandomDouble" => {
94 let [lo, hi] = unwrap_tuple(arg);
95 let lo = lo.unwrap_double();
96 let hi = hi.unwrap_double();
97 if lo > hi {
98 Err(Error::EmptyRange(arg_span))
99 } else {
100 Ok(Value::Double(rng.gen_range(lo..=hi)))
101 }
102 }
103 #[allow(clippy::cast_possible_truncation)]
104 "Truncate" => Ok(Value::Int(arg.unwrap_double() as i64)),
105 "__quantum__rt__qubit_allocate" => Ok(Value::Qubit(Qubit(sim.qubit_allocate()))),
106 "__quantum__rt__qubit_release" => {
107 let qubit = arg.unwrap_qubit().0;
108 if sim.qubit_is_zero(qubit) {
109 sim.qubit_release(qubit);
110 Ok(Value::unit())
111 } else {
112 Err(Error::ReleasedQubitNotZero(qubit, arg_span))
113 }
114 }
115 "__quantum__qis__ccx__body" => {
116 three_qubit_gate(|ctl0, ctl1, q| sim.ccx(ctl0, ctl1, q), arg, arg_span)
117 }
118 "__quantum__qis__cx__body" => two_qubit_gate(|ctl, q| sim.cx(ctl, q), arg, arg_span),
119 "__quantum__qis__cy__body" => two_qubit_gate(|ctl, q| sim.cy(ctl, q), arg, arg_span),
120 "__quantum__qis__cz__body" => two_qubit_gate(|ctl, q| sim.cz(ctl, q), arg, arg_span),
121 "__quantum__qis__rx__body" => {
122 one_qubit_rotation(|theta, q| sim.rx(theta, q), arg, arg_span)
123 }
124 "__quantum__qis__rxx__body" => {
125 two_qubit_rotation(|theta, q0, q1| sim.rxx(theta, q0, q1), arg, arg_span)
126 }
127 "__quantum__qis__ry__body" => {
128 one_qubit_rotation(|theta, q| sim.ry(theta, q), arg, arg_span)
129 }
130 "__quantum__qis__ryy__body" => {
131 two_qubit_rotation(|theta, q0, q1| sim.ryy(theta, q0, q1), arg, arg_span)
132 }
133 "__quantum__qis__rz__body" => {
134 one_qubit_rotation(|theta, q| sim.rz(theta, q), arg, arg_span)
135 }
136 "__quantum__qis__rzz__body" => {
137 two_qubit_rotation(|theta, q0, q1| sim.rzz(theta, q0, q1), arg, arg_span)
138 }
139 "__quantum__qis__h__body" => Ok(one_qubit_gate(|q| sim.h(q), arg)),
140 "__quantum__qis__s__body" => Ok(one_qubit_gate(|q| sim.s(q), arg)),
141 "__quantum__qis__s__adj" => Ok(one_qubit_gate(|q| sim.sadj(q), arg)),
142 "__quantum__qis__t__body" => Ok(one_qubit_gate(|q| sim.t(q), arg)),
143 "__quantum__qis__t__adj" => Ok(one_qubit_gate(|q| sim.tadj(q), arg)),
144 "__quantum__qis__x__body" => Ok(one_qubit_gate(|q| sim.x(q), arg)),
145 "__quantum__qis__y__body" => Ok(one_qubit_gate(|q| sim.y(q), arg)),
146 "__quantum__qis__z__body" => Ok(one_qubit_gate(|q| sim.z(q), arg)),
147 "__quantum__qis__swap__body" => two_qubit_gate(|q0, q1| sim.swap(q0, q1), arg, arg_span),
148 "__quantum__qis__reset__body" => Ok(one_qubit_gate(|q| sim.reset(q), arg)),
149 "__quantum__qis__m__body" => Ok(Value::Result(sim.m(arg.unwrap_qubit().0).into())),
150 "__quantum__qis__mresetz__body" => {
151 Ok(Value::Result(sim.mresetz(arg.unwrap_qubit().0).into()))
152 }
153 _ => {
154 if let Some(result) = sim.custom_intrinsic(name, arg) {
155 match result {
156 Ok(value) => Ok(value),
157 Err(message) => Err(Error::IntrinsicFail(name.to_string(), message, name_span)),
158 }
159 } else {
160 Err(Error::UnknownIntrinsic(name.to_string(), name_span))
161 }
162 }
163 }
164}
165
166fn one_qubit_gate(mut gate: impl FnMut(usize), arg: Value) -> Value {
167 gate(arg.unwrap_qubit().0);
168 Value::unit()
169}
170
171fn two_qubit_gate(
172 mut gate: impl FnMut(usize, usize),
173 arg: Value,
174 arg_span: PackageSpan,
175) -> Result<Value, Error> {
176 let [x, y] = unwrap_tuple(arg);
177 if x == y {
178 Err(Error::QubitUniqueness(arg_span))
179 } else {
180 gate(x.unwrap_qubit().0, y.unwrap_qubit().0);
181 Ok(Value::unit())
182 }
183}
184
185fn one_qubit_rotation(
186 mut gate: impl FnMut(f64, usize),
187 arg: Value,
188 arg_span: PackageSpan,
189) -> Result<Value, Error> {
190 let [x, y] = unwrap_tuple(arg);
191 let angle = x.unwrap_double();
192 if angle.is_nan() || angle.is_infinite() {
193 Err(Error::InvalidRotationAngle(angle, arg_span))
194 } else {
195 gate(angle, y.unwrap_qubit().0);
196 Ok(Value::unit())
197 }
198}
199
200fn three_qubit_gate(
201 mut gate: impl FnMut(usize, usize, usize),
202 arg: Value,
203 arg_span: PackageSpan,
204) -> Result<Value, Error> {
205 let [x, y, z] = unwrap_tuple(arg);
206 if x == y || y == z || x == z {
207 Err(Error::QubitUniqueness(arg_span))
208 } else {
209 gate(x.unwrap_qubit().0, y.unwrap_qubit().0, z.unwrap_qubit().0);
210 Ok(Value::unit())
211 }
212}
213
214fn two_qubit_rotation(
215 mut gate: impl FnMut(f64, usize, usize),
216 arg: Value,
217 arg_span: PackageSpan,
218) -> Result<Value, Error> {
219 let [x, y, z] = unwrap_tuple(arg);
220 let angle = x.unwrap_double();
221 if y == z {
222 Err(Error::QubitUniqueness(arg_span))
223 } else if angle.is_nan() || angle.is_infinite() {
224 Err(Error::InvalidRotationAngle(angle, arg_span))
225 } else {
226 gate(angle, y.unwrap_qubit().0, z.unwrap_qubit().0);
227 Ok(Value::unit())
228 }
229}
230
231fn unwrap_tuple<const N: usize>(value: Value) -> [Value; N] {
232 let values = value.unwrap_tuple();
233 array::from_fn(|i| values[i].clone())
234}