microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.1.3

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_eval/src/val.rs

358lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use num_bigint::BigInt;
5use qsc_fir::fir::{Pauli, StoreItemId};
6use std::{
7 fmt::{self, Display, Formatter},
8 iter,
9 rc::Rc,
10};
11
12pub(super) const DEFAULT_RANGE_STEP: i64 = 1;
13
14#[derive(Clone, Debug, PartialEq)]
15pub enum Value {
16 Array(Rc<Vec<Value>>),
17 BigInt(BigInt),
18 Bool(bool),
19 Closure(Rc<[Value]>, StoreItemId, FunctorApp),
20 Double(f64),
21 Global(StoreItemId, FunctorApp),
22 Int(i64),
23 Pauli(Pauli),
24 Qubit(Qubit),
25 Range(Option<i64>, i64, Option<i64>),
26 Result(Result),
27 String(Rc<str>),
28 Tuple(Rc<[Value]>),
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
32pub enum Result {
33 Val(bool),
34 Id(usize),
35}
36
37impl Result {
38 /// Convert the `Result` into a bool
39 /// # Panics
40 /// This will panic if the `Result` is not a `Result::Val`.
41 #[must_use]
42 pub fn unwrap_bool(self) -> bool {
43 match self {
44 Self::Val(v) => v,
45 Self::Id(_) => panic!("cannot unwrap Result::Id as bool"),
46 }
47 }
48
49 /// Convert the `Result` into an id
50 /// # Panics
51 /// This will panic if the `Result` is not a `Result::Id`.
52 #[must_use]
53 pub fn unwrap_id(self) -> usize {
54 match self {
55 Self::Val(_) => panic!("cannot unwrap Result::Val as id"),
56 Self::Id(v) => v,
57 }
58 }
59}
60
61impl From<bool> for Result {
62 fn from(val: bool) -> Self {
63 Self::Val(val)
64 }
65}
66
67impl From<usize> for Result {
68 fn from(val: usize) -> Self {
69 Self::Id(val)
70 }
71}
72
73#[derive(Clone, Copy, Debug, PartialEq)]
74pub struct Qubit(pub usize);
75
76#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
77pub struct FunctorApp {
78 /// An invocation is either adjoint or not, with each successive use of `Adjoint` functor switching
79 /// between the two, so a bool is sufficient to track.
80 pub adjoint: bool,
81
82 /// An invocation can have multiple `Controlled` functors with each one adding another layer of updates
83 /// to the argument tuple, so the functor application must be tracked with a count.
84 pub controlled: u8,
85}
86
87impl Display for FunctorApp {
88 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
89 let controlleds = iter::repeat("Controlled").take(self.controlled.into());
90 let adjoint = iter::once("Adjoint").filter(|_| self.adjoint);
91 join(f, controlleds.chain(adjoint), " ")
92 }
93}
94
95impl Display for Value {
96 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
97 match self {
98 Value::Array(arr) => {
99 write!(f, "[")?;
100 join(f, arr.iter(), ", ")?;
101 write!(f, "]")
102 }
103 Value::BigInt(v) => write!(f, "{v}"),
104 Value::Bool(v) => write!(f, "{v}"),
105 Value::Closure(..) => f.write_str("<closure>"),
106 Value::Double(v) => {
107 if (v.floor() - v.ceil()).abs() < f64::EPSILON {
108 // The value is a whole number, which by convention is displayed with one decimal point
109 // to differentiate it from an integer value.
110 write!(f, "{v:.1}")
111 } else {
112 write!(f, "{v}")
113 }
114 }
115 Value::Global(id, functor) if functor == &FunctorApp::default() => id.fmt(f),
116 Value::Global(id, functor) => write!(f, "{functor} {id}"),
117 Value::Int(v) => write!(f, "{v}"),
118 Value::Pauli(v) => match v {
119 Pauli::I => write!(f, "PauliI"),
120 Pauli::X => write!(f, "PauliX"),
121 Pauli::Z => write!(f, "PauliZ"),
122 Pauli::Y => write!(f, "PauliY"),
123 },
124 Value::Qubit(v) => write!(f, "Qubit{}", (v.0)),
125 &Value::Range(start, step, end) => match (start, step, end) {
126 (Some(start), DEFAULT_RANGE_STEP, Some(end)) => write!(f, "{start}..{end}"),
127 (Some(start), DEFAULT_RANGE_STEP, None) => write!(f, "{start}..."),
128 (Some(start), step, Some(end)) => write!(f, "{start}..{step}..{end}"),
129 (Some(start), step, None) => write!(f, "{start}..{step}..."),
130 (None, DEFAULT_RANGE_STEP, Some(end)) => write!(f, "...{end}"),
131 (None, DEFAULT_RANGE_STEP, None) => write!(f, "..."),
132 (None, step, Some(end)) => write!(f, "...{step}..{end}"),
133 (None, step, None) => write!(f, "...{step}..."),
134 },
135 Value::Result(v) => {
136 if v.unwrap_bool() {
137 write!(f, "One")
138 } else {
139 write!(f, "Zero")
140 }
141 }
142 Value::String(v) => write!(f, "{v}"),
143 Value::Tuple(tup) => {
144 write!(f, "(")?;
145 join(f, tup.iter(), ", ")?;
146 if tup.len() == 1 {
147 write!(f, ",")?;
148 }
149 write!(f, ")")
150 }
151 }
152 }
153}
154
155thread_local! {
156 static UNIT: Rc<[Value; 0]> = Rc::new([]);
157}
158
159impl Value {
160 pub const RESULT_ZERO: Self = Self::Result(Result::Val(false));
161 pub const RESULT_ONE: Self = Self::Result(Result::Val(true));
162
163 #[must_use]
164 pub fn unit() -> Self {
165 UNIT.with(|unit| Self::Tuple(unit.clone()))
166 }
167
168 /// Convert the [Value] into an array of [Value]
169 /// # Panics
170 /// This will panic if the [Value] is not a [`Value::Array`].
171 #[must_use]
172 pub fn unwrap_array(self) -> Rc<Vec<Self>> {
173 let Value::Array(v) = self else {
174 panic!("value should be Array, got {}", self.type_name());
175 };
176 v
177 }
178
179 /// Updates a value in an array in-place.
180 /// # Panics
181 /// This will panic if the [Value] is not a [`Value::Array`].
182 pub fn update_array(&mut self, index: usize, value: Self) -> core::result::Result<(), usize> {
183 let Value::Array(arr) = self else {
184 panic!("value should be Array, got {}", self.type_name());
185 };
186 let arr = Rc::get_mut(arr).expect("array should be uniquely referenced");
187 match arr.get_mut(index) {
188 Some(v) => {
189 *v = value;
190 Ok(())
191 }
192 None => Err(index),
193 }
194 }
195
196 /// Appends a value to an array in-place.
197 /// # Panics
198 /// This will panic if the [Value] is not a [`Value::Array`].
199 pub fn append_array(&mut self, value: Self) {
200 let Value::Array(arr) = self else {
201 panic!("value should be Array, got {}", self.type_name());
202 };
203 let arr = Rc::get_mut(arr).expect("array should be uniquely referenced");
204 let append_arr = value.unwrap_array();
205 arr.extend_from_slice(&append_arr);
206 }
207
208 /// Convert the [Value] into a `BigInt`
209 /// # Panics
210 /// This will panic if the [Value] is not a [`Value::BigInt`].
211 #[must_use]
212 pub fn unwrap_big_int(self) -> BigInt {
213 let Value::BigInt(v) = self else {
214 panic!("value should be BigInt, got {}", self.type_name());
215 };
216 v
217 }
218
219 /// Convert the [Value] into a bool
220 /// # Panics
221 /// This will panic if the [Value] is not a [`Value::Bool`].
222 #[must_use]
223 pub fn unwrap_bool(self) -> bool {
224 let Value::Bool(v) = self else {
225 panic!("value should be Bool, got {}", self.type_name());
226 };
227 v
228 }
229
230 /// Convert the [Value] into a double
231 /// # Panics
232 /// This will panic if the [Value] is not a [`Value::Double`].
233 #[must_use]
234 pub fn unwrap_double(self) -> f64 {
235 let Value::Double(v) = self else {
236 panic!("value should be Double, got {}", self.type_name());
237 };
238 v
239 }
240
241 /// Convert the [Value] into a global tuple
242 /// # Panics
243 /// This will panic if the [Value] is not a [`Value::Global`].
244 #[must_use]
245 pub fn unwrap_global(self) -> (StoreItemId, FunctorApp) {
246 let Value::Global(id, functor) = self else {
247 panic!("value should be Global, got {}", self.type_name());
248 };
249 (id, functor)
250 }
251
252 /// Convert the [Value] into an integer
253 /// # Panics
254 /// This will panic if the [Value] is not a [`Value::Int`].
255 #[must_use]
256 pub fn unwrap_int(self) -> i64 {
257 let Value::Int(v) = self else {
258 panic!("value should be Int, got {}", self.type_name());
259 };
260 v
261 }
262
263 /// Convert the [Value] into a Pauli
264 /// # Panics
265 /// This will panic if the [Value] is not a [`Value::Pauli`].
266 #[must_use]
267 pub fn unwrap_pauli(self) -> Pauli {
268 let Value::Pauli(v) = self else {
269 panic!("value should be Pauli, got {}", self.type_name());
270 };
271 v
272 }
273
274 /// Convert the [Value] into a qubit
275 /// # Panics
276 /// This will panic if the [Value] is not a [`Value::Qubit`].
277 #[must_use]
278 pub fn unwrap_qubit(self) -> Qubit {
279 let Value::Qubit(v) = self else {
280 panic!("value should be Qubit, got {}", self.type_name());
281 };
282 v
283 }
284
285 /// Convert the [Value] into a range tuple
286 /// # Panics
287 /// This will panic if the [Value] is not a [`Value::Range`].
288 #[must_use]
289 pub fn unwrap_range(self) -> (Option<i64>, i64, Option<i64>) {
290 let Value::Range(start, step, end) = self else {
291 panic!("value should be Range, got {}", self.type_name());
292 };
293 (start, step, end)
294 }
295
296 /// Convert the [Value] into a measurement result
297 /// # Panics
298 /// This will panic if the [Value] is not a [`Value::Result`].
299 #[must_use]
300 pub fn unwrap_result(self) -> bool {
301 let Value::Result(v) = self else {
302 panic!("value should be Result, got {}", self.type_name());
303 };
304 v.unwrap_bool()
305 }
306
307 /// Convert the [Value] into a string
308 /// # Panics
309 /// This will panic if the [Value] is not a [`Value::String`].
310 #[must_use]
311 pub fn unwrap_string(self) -> Rc<str> {
312 let Value::String(v) = self else {
313 panic!("value should be String, got {}", self.type_name());
314 };
315 v
316 }
317
318 /// Convert the [Value] into an array of [Value]
319 /// # Panics
320 /// This will panic if the [Value] is not a [`Value::Tuple`].
321 #[must_use]
322 pub fn unwrap_tuple(self) -> Rc<[Self]> {
323 let Value::Tuple(v) = self else {
324 panic!("value should be Tuple, got {}", self.type_name());
325 };
326 v
327 }
328
329 #[must_use]
330 pub fn type_name(&self) -> &'static str {
331 match self {
332 Value::Array(_) => "Array",
333 Value::BigInt(_) => "BigInt",
334 Value::Bool(_) => "Bool",
335 Value::Closure(..) => "Closure",
336 Value::Double(_) => "Double",
337 Value::Global(..) => "Global",
338 Value::Int(_) => "Int",
339 Value::Pauli(_) => "Pauli",
340 Value::Qubit(_) => "Qubit",
341 Value::Range(..) => "Range",
342 Value::Result(_) => "Result",
343 Value::String(_) => "String",
344 Value::Tuple(_) => "Tuple",
345 }
346 }
347}
348
349fn join(f: &mut Formatter, mut vals: impl Iterator<Item = impl Display>, sep: &str) -> fmt::Result {
350 if let Some(v) = vals.next() {
351 v.fmt(f)?;
352 }
353 for v in vals {
354 write!(f, "{sep}")?;
355 v.fmt(f)?;
356 }
357 Ok(())
358}
359