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/val.rs

328lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use num_bigint::BigInt;
5use qsc_data_structures::{display::join, functors::FunctorApp};
6use qsc_fir::fir::{Pauli, StoreItemId};
7use std::{
8 fmt::{self, Display, Formatter},
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
76impl Display for Value {
77 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
78 match self {
79 Value::Array(arr) => {
80 write!(f, "[")?;
81 join(f, arr.iter(), ", ")?;
82 write!(f, "]")
83 }
84 Value::BigInt(v) => write!(f, "{v}"),
85 Value::Bool(v) => write!(f, "{v}"),
86 Value::Closure(..) => f.write_str("<closure>"),
87 Value::Double(v) => {
88 if (v.floor() - v.ceil()).abs() < f64::EPSILON {
89 // The value is a whole number, which by convention is displayed with one decimal point
90 // to differentiate it from an integer value.
91 write!(f, "{v:.1}")
92 } else {
93 write!(f, "{v}")
94 }
95 }
96 Value::Global(id, functor) if functor == &FunctorApp::default() => id.fmt(f),
97 Value::Global(id, functor) => write!(f, "{functor} {id}"),
98 Value::Int(v) => write!(f, "{v}"),
99 Value::Pauli(v) => match v {
100 Pauli::I => write!(f, "PauliI"),
101 Pauli::X => write!(f, "PauliX"),
102 Pauli::Z => write!(f, "PauliZ"),
103 Pauli::Y => write!(f, "PauliY"),
104 },
105 Value::Qubit(v) => write!(f, "Qubit{}", (v.0)),
106 &Value::Range(start, step, end) => match (start, step, end) {
107 (Some(start), DEFAULT_RANGE_STEP, Some(end)) => write!(f, "{start}..{end}"),
108 (Some(start), DEFAULT_RANGE_STEP, None) => write!(f, "{start}..."),
109 (Some(start), step, Some(end)) => write!(f, "{start}..{step}..{end}"),
110 (Some(start), step, None) => write!(f, "{start}..{step}..."),
111 (None, DEFAULT_RANGE_STEP, Some(end)) => write!(f, "...{end}"),
112 (None, DEFAULT_RANGE_STEP, None) => write!(f, "..."),
113 (None, step, Some(end)) => write!(f, "...{step}..{end}"),
114 (None, step, None) => write!(f, "...{step}..."),
115 },
116 Value::Result(v) => {
117 if v.unwrap_bool() {
118 write!(f, "One")
119 } else {
120 write!(f, "Zero")
121 }
122 }
123 Value::String(v) => write!(f, "{v}"),
124 Value::Tuple(tup) => {
125 write!(f, "(")?;
126 join(f, tup.iter(), ", ")?;
127 if tup.len() == 1 {
128 write!(f, ",")?;
129 }
130 write!(f, ")")
131 }
132 }
133 }
134}
135
136thread_local! {
137 static UNIT: Rc<[Value; 0]> = Rc::new([]);
138}
139
140impl Value {
141 pub const RESULT_ZERO: Self = Self::Result(Result::Val(false));
142 pub const RESULT_ONE: Self = Self::Result(Result::Val(true));
143
144 #[must_use]
145 pub fn unit() -> Self {
146 UNIT.with(|unit| Self::Tuple(unit.clone()))
147 }
148
149 /// Convert the [Value] into an array of [Value]
150 /// # Panics
151 /// This will panic if the [Value] is not a [`Value::Array`].
152 #[must_use]
153 pub fn unwrap_array(self) -> Rc<Vec<Self>> {
154 let Value::Array(v) = self else {
155 panic!("value should be Array, got {}", self.type_name());
156 };
157 v
158 }
159
160 /// Updates a value in an array in-place.
161 /// # Panics
162 /// This will panic if the [Value] is not a [`Value::Array`].
163 pub fn update_array(&mut self, index: usize, value: Self) -> core::result::Result<(), usize> {
164 let Value::Array(arr) = self else {
165 panic!("value should be Array, got {}", self.type_name());
166 };
167 let arr = Rc::get_mut(arr).expect("array should be uniquely referenced");
168 match arr.get_mut(index) {
169 Some(v) => {
170 *v = value;
171 Ok(())
172 }
173 None => Err(index),
174 }
175 }
176
177 /// Appends a value to an array in-place.
178 /// # Panics
179 /// This will panic if the [Value] is not a [`Value::Array`].
180 pub fn append_array(&mut self, value: Self) {
181 let Value::Array(arr) = self else {
182 panic!("value should be Array, got {}", self.type_name());
183 };
184 let arr = Rc::get_mut(arr).expect("array should be uniquely referenced");
185 let append_arr = value.unwrap_array();
186 arr.extend_from_slice(&append_arr);
187 }
188
189 /// Convert the [Value] into a `BigInt`
190 /// # Panics
191 /// This will panic if the [Value] is not a [`Value::BigInt`].
192 #[must_use]
193 pub fn unwrap_big_int(self) -> BigInt {
194 let Value::BigInt(v) = self else {
195 panic!("value should be BigInt, got {}", self.type_name());
196 };
197 v
198 }
199
200 /// Convert the [Value] into a bool
201 /// # Panics
202 /// This will panic if the [Value] is not a [`Value::Bool`].
203 #[must_use]
204 pub fn unwrap_bool(self) -> bool {
205 let Value::Bool(v) = self else {
206 panic!("value should be Bool, got {}", self.type_name());
207 };
208 v
209 }
210
211 /// Convert the [Value] into a double
212 /// # Panics
213 /// This will panic if the [Value] is not a [`Value::Double`].
214 #[must_use]
215 pub fn unwrap_double(self) -> f64 {
216 let Value::Double(v) = self else {
217 panic!("value should be Double, got {}", self.type_name());
218 };
219 v
220 }
221
222 /// Convert the [Value] into a global tuple
223 /// # Panics
224 /// This will panic if the [Value] is not a [`Value::Global`].
225 #[must_use]
226 pub fn unwrap_global(self) -> (StoreItemId, FunctorApp) {
227 let Value::Global(id, functor) = self else {
228 panic!("value should be Global, got {}", self.type_name());
229 };
230 (id, functor)
231 }
232
233 /// Convert the [Value] into an integer
234 /// # Panics
235 /// This will panic if the [Value] is not a [`Value::Int`].
236 #[must_use]
237 pub fn unwrap_int(self) -> i64 {
238 let Value::Int(v) = self else {
239 panic!("value should be Int, got {}", self.type_name());
240 };
241 v
242 }
243
244 /// Convert the [Value] into a Pauli
245 /// # Panics
246 /// This will panic if the [Value] is not a [`Value::Pauli`].
247 #[must_use]
248 pub fn unwrap_pauli(self) -> Pauli {
249 let Value::Pauli(v) = self else {
250 panic!("value should be Pauli, got {}", self.type_name());
251 };
252 v
253 }
254
255 /// Convert the [Value] into a qubit
256 /// # Panics
257 /// This will panic if the [Value] is not a [`Value::Qubit`].
258 #[must_use]
259 pub fn unwrap_qubit(self) -> Qubit {
260 let Value::Qubit(v) = self else {
261 panic!("value should be Qubit, got {}", self.type_name());
262 };
263 v
264 }
265
266 /// Convert the [Value] into a range tuple
267 /// # Panics
268 /// This will panic if the [Value] is not a [`Value::Range`].
269 #[must_use]
270 pub fn unwrap_range(self) -> (Option<i64>, i64, Option<i64>) {
271 let Value::Range(start, step, end) = self else {
272 panic!("value should be Range, got {}", self.type_name());
273 };
274 (start, step, end)
275 }
276
277 /// Convert the [Value] into a measurement result
278 /// # Panics
279 /// This will panic if the [Value] is not a [`Value::Result`].
280 #[must_use]
281 pub fn unwrap_result(self) -> bool {
282 let Value::Result(v) = self else {
283 panic!("value should be Result, got {}", self.type_name());
284 };
285 v.unwrap_bool()
286 }
287
288 /// Convert the [Value] into a string
289 /// # Panics
290 /// This will panic if the [Value] is not a [`Value::String`].
291 #[must_use]
292 pub fn unwrap_string(self) -> Rc<str> {
293 let Value::String(v) = self else {
294 panic!("value should be String, got {}", self.type_name());
295 };
296 v
297 }
298
299 /// Convert the [Value] into an array of [Value]
300 /// # Panics
301 /// This will panic if the [Value] is not a [`Value::Tuple`].
302 #[must_use]
303 pub fn unwrap_tuple(self) -> Rc<[Self]> {
304 let Value::Tuple(v) = self else {
305 panic!("value should be Tuple, got {}", self.type_name());
306 };
307 v
308 }
309
310 #[must_use]
311 pub fn type_name(&self) -> &'static str {
312 match self {
313 Value::Array(_) => "Array",
314 Value::BigInt(_) => "BigInt",
315 Value::Bool(_) => "Bool",
316 Value::Closure(..) => "Closure",
317 Value::Double(_) => "Double",
318 Value::Global(..) => "Global",
319 Value::Int(_) => "Int",
320 Value::Pauli(_) => "Pauli",
321 Value::Qubit(_) => "Qubit",
322 Value::Range(..) => "Range",
323 Value::Result(_) => "Result",
324 Value::String(_) => "String",
325 Value::Tuple(_) => "Tuple",
326 }
327 }
328}
329