microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/num2-sim

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/resource_estimator/src/system/modeling/physical_qubit.rs

605lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#[cfg(test)]
5mod tests;
6
7use super::super::{
8 constants::{
9 INSTRUCTION_SET, ONE_QUBIT_GATE_ERROR_RATE, ONE_QUBIT_GATE_TIME,
10 ONE_QUBIT_MEASUREMENT_ERROR_RATE, ONE_QUBIT_MEASUREMENT_TIME, T_GATE_ERROR_RATE,
11 },
12 serialization::{f64_nan, time},
13};
14use serde::{Deserialize, Serialize, de::Error};
15
16/// Physical qubit classification.
17///
18/// The physical qubit can be either `gate_based` or `Majorana` (use these
19/// values in the serialized file formats).
20#[derive(Eq, PartialEq, Copy, Clone, Debug)]
21pub enum PhysicalInstructionSet {
22 GateBased,
23 Majorana,
24}
25
26/// This checks whether in a list of required fields some of them are not
27/// specified and then generates an error with all undefined fields.
28///
29/// The first element in each tuple is `true` if and only if the field is not
30/// specified.
31fn check_required_fields(fields: &[(bool, &str)]) -> Result<(), serde_json::error::Error> {
32 let missing_fields: Vec<_> = fields
33 .iter()
34 .filter(|(is_none, _)| *is_none)
35 .map(|(_, name)| format!("`{name}`"))
36 .collect();
37
38 if missing_fields.is_empty() {
39 Ok(())
40 } else {
41 let joined = missing_fields.join(", ");
42 Err(serde::de::Error::custom(format!("missing fields {joined}")))
43 }
44}
45
46/// Physical qubit model.
47///
48/// This struct models a physical qubit.
49///
50/// # Qubit types
51///
52/// We can model two different qubit types. These come with different fields;
53/// some of them require values to be specified, while some others can be
54/// derived. See `input_params.md` file in docs folder for more details.
55#[derive(Serialize, Deserialize, Debug, PartialEq)]
56#[serde(
57 tag = "instructionSet",
58 try_from = "serde_json::Map<String, serde_json::Value>"
59)]
60pub enum PhysicalQubit {
61 GateBased(GateBasedPhysicalQubit),
62 Majorana(MajoranaQubit),
63}
64
65impl PhysicalQubit {
66 #[must_use]
67 pub fn qubit_gate_ns_e3() -> Self {
68 Self::GateBased(GateBasedPhysicalQubit::qubit_gate_ns_e3())
69 }
70
71 #[must_use]
72 pub fn qubit_gate_ns_e4() -> Self {
73 Self::GateBased(GateBasedPhysicalQubit::qubit_gate_ns_e4())
74 }
75
76 #[must_use]
77 pub fn qubit_gate_us_e3() -> Self {
78 Self::GateBased(GateBasedPhysicalQubit::qubit_gate_us_e3())
79 }
80
81 #[must_use]
82 pub fn qubit_gate_us_e4() -> Self {
83 Self::GateBased(GateBasedPhysicalQubit::qubit_gate_us_e4())
84 }
85
86 #[must_use]
87 pub fn qubit_maj_ns_e4() -> Self {
88 Self::Majorana(MajoranaQubit::qubit_maj_ns_e4())
89 }
90
91 #[must_use]
92 pub fn qubit_maj_ns_e6() -> Self {
93 Self::Majorana(MajoranaQubit::qubit_maj_ns_e6())
94 }
95
96 #[must_use]
97 pub fn instruction_set(&self) -> super::PhysicalInstructionSet {
98 match self {
99 Self::GateBased(_) => super::PhysicalInstructionSet::GateBased,
100 Self::Majorana(_) => super::PhysicalInstructionSet::Majorana,
101 }
102 }
103
104 #[must_use]
105 pub fn t_gate_time(&self) -> u64 {
106 match self {
107 Self::GateBased(gate_based) => {
108 gate_based.t_gate_time.expect("T gate time should be set")
109 }
110 Self::Majorana(majorana) => majorana.t_gate_time.expect("T gate time should be set"),
111 }
112 }
113
114 #[must_use]
115 pub fn t_gate_error_rate(&self) -> f64 {
116 match self {
117 Self::GateBased(gate_based) => gate_based.t_gate_error_rate,
118 Self::Majorana(majorana) => majorana.t_gate_error_rate,
119 }
120 }
121
122 #[must_use]
123 pub fn one_qubit_measurement_time(&self) -> u64 {
124 match self {
125 Self::GateBased(gate_based) => gate_based
126 .one_qubit_measurement_time
127 .expect("measurement time should be set"),
128 Self::Majorana(majorana) => majorana
129 .one_qubit_measurement_time
130 .expect("measurement time should"),
131 }
132 }
133
134 #[must_use]
135 pub fn clifford_error_rate(&self) -> f64 {
136 match self {
137 Self::GateBased(gate_based) => gate_based
138 .one_qubit_gate_error_rate
139 .max(gate_based.two_qubit_gate_error_rate)
140 .max(gate_based.idle_error_rate),
141 Self::Majorana(majorana) => majorana
142 .idle_error_rate
143 .max(majorana.one_qubit_measurement_error_rate.process())
144 .max(majorana.two_qubit_joint_measurement_error_rate.process()),
145 }
146 }
147
148 #[must_use]
149 pub fn readout_error_rate(&self) -> f64 {
150 match self {
151 Self::GateBased(gate_based) => gate_based.one_qubit_measurement_error_rate,
152 Self::Majorana(majorana) => majorana
153 .one_qubit_measurement_error_rate
154 .readout()
155 .max(majorana.two_qubit_joint_measurement_error_rate.readout()),
156 }
157 }
158}
159
160#[derive(Serialize, Deserialize, Debug, PartialEq)]
161#[serde(rename_all = "camelCase", deny_unknown_fields)]
162pub struct GateBasedPhysicalQubit {
163 #[serde(default)]
164 pub name: String,
165 #[serde(default, with = "time")]
166 pub one_qubit_measurement_time: Option<u64>,
167 #[serde(default, with = "time")]
168 pub one_qubit_gate_time: Option<u64>,
169 #[serde(default, with = "time")]
170 pub two_qubit_gate_time: Option<u64>,
171 #[serde(default, with = "time")]
172 pub t_gate_time: Option<u64>,
173 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
174 pub one_qubit_measurement_error_rate: f64,
175 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
176 pub one_qubit_gate_error_rate: f64,
177 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
178 pub two_qubit_gate_error_rate: f64,
179 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
180 pub t_gate_error_rate: f64,
181 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
182 pub idle_error_rate: f64,
183}
184
185#[derive(Serialize, Deserialize, Debug, PartialEq)]
186#[serde(rename_all = "camelCase", deny_unknown_fields)]
187pub struct MajoranaQubit {
188 #[serde(default)]
189 pub name: String,
190 #[serde(default, with = "time")]
191 pub one_qubit_measurement_time: Option<u64>,
192 #[serde(default, with = "time")]
193 pub two_qubit_joint_measurement_time: Option<u64>,
194 #[serde(default, with = "time")]
195 pub t_gate_time: Option<u64>,
196 #[serde(default)]
197 pub one_qubit_measurement_error_rate: MeasurementErrorRate,
198 #[serde(default)]
199 pub two_qubit_joint_measurement_error_rate: MeasurementErrorRate,
200 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
201 pub t_gate_error_rate: f64,
202 #[serde(default = "f64_nan", deserialize_with = "deserialize_error_rate")]
203 pub idle_error_rate: f64,
204}
205
206#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
207#[serde(untagged)]
208pub enum MeasurementErrorRate {
209 Simple(#[serde(deserialize_with = "deserialize_error_rate")] f64),
210 Detailed {
211 #[serde(deserialize_with = "deserialize_error_rate")]
212 process: f64,
213 #[serde(deserialize_with = "deserialize_error_rate")]
214 readout: f64,
215 },
216}
217
218impl Default for PhysicalQubit {
219 fn default() -> Self {
220 Self::GateBased(GateBasedPhysicalQubit::default())
221 }
222}
223
224impl TryFrom<serde_json::Map<String, serde_json::Value>> for PhysicalQubit {
225 type Error = serde_json::Error;
226
227 fn try_from(mut map: serde_json::Map<String, serde_json::Value>) -> Result<Self, Self::Error> {
228 use serde_json::Value;
229
230 // check if there is an instruction set
231 if let Some(Value::String(instruction_set)) = map.remove(INSTRUCTION_SET) {
232 match instruction_set.as_str() {
233 "gate_based" | "gateBased" | "gate-based" | "GateBased" => {
234 let qubit: GateBasedPhysicalQubit = serde_json::from_value(Value::Object(map))?;
235 Ok(Self::GateBased(qubit.normalized()?))
236 }
237 "Majorana" | "majorana" => {
238 let qubit: MajoranaQubit = serde_json::from_value(Value::Object(map))?;
239 Ok(Self::Majorana(qubit.normalized()?))
240 }
241 _ => Err(serde_json::Error::invalid_value(
242 serde::de::Unexpected::Str(&instruction_set),
243 &"expected \"GateBased\" or \"Majorana\" as value for instructionSet",
244 )),
245 }
246 } else if let Some(Value::String(name)) = map.get("name") {
247 match name.as_str() {
248 "qubit_gate_ns_e3" | "qubit_gate_ns_e4" | "qubit_gate_us_e3"
249 | "qubit_gate_us_e4" => {
250 let qubit: GateBasedPhysicalQubit = serde_json::from_value(Value::Object(map))?;
251 Ok(Self::GateBased(qubit.normalized()?))
252 }
253 "qubit_maj_ns_e4" | "qubit_maj_ns_e6" => {
254 let qubit: MajoranaQubit = serde_json::from_value(Value::Object(map))?;
255 Ok(Self::Majorana(qubit.normalized()?))
256 }
257 _ => Err(serde_json::Error::missing_field(INSTRUCTION_SET)),
258 }
259 } else {
260 Err(serde_json::Error::missing_field("name or instructionSet"))
261 }
262 }
263}
264
265impl GateBasedPhysicalQubit {
266 fn from_default_name(name: &str) -> Option<Self> {
267 match name {
268 "qubit_gate_ns_e3" => Some(Self::qubit_gate_ns_e3()),
269 "qubit_gate_ns_e4" => Some(Self::qubit_gate_ns_e4()),
270 "qubit_gate_us_e3" => Some(Self::qubit_gate_us_e3()),
271 "qubit_gate_us_e4" => Some(Self::qubit_gate_us_e4()),
272 _ => None,
273 }
274 }
275
276 #[must_use]
277 pub fn qubit_gate_ns_e3() -> Self {
278 Self {
279 name: "qubit_gate_ns_e3".into(),
280 one_qubit_measurement_time: Some(100),
281 one_qubit_gate_time: Some(50),
282 two_qubit_gate_time: Some(50),
283 t_gate_time: Some(50),
284 one_qubit_measurement_error_rate: 1e-3,
285 one_qubit_gate_error_rate: 1e-3,
286 two_qubit_gate_error_rate: 1e-3,
287 t_gate_error_rate: 1e-3,
288 idle_error_rate: 1e-3,
289 }
290 }
291
292 #[must_use]
293 pub fn qubit_gate_ns_e4() -> Self {
294 Self {
295 name: "qubit_gate_ns_e4".into(),
296 one_qubit_measurement_time: Some(100),
297 one_qubit_gate_time: Some(50),
298 two_qubit_gate_time: Some(50),
299 t_gate_time: Some(50),
300 one_qubit_measurement_error_rate: 1e-4,
301 one_qubit_gate_error_rate: 1e-4,
302 two_qubit_gate_error_rate: 1e-4,
303 t_gate_error_rate: 1e-4,
304 idle_error_rate: 1e-4,
305 }
306 }
307
308 #[must_use]
309 pub fn qubit_gate_us_e3() -> Self {
310 Self {
311 name: "qubit_gate_us_e3".into(),
312 one_qubit_measurement_time: Some(100_000),
313 one_qubit_gate_time: Some(100_000),
314 two_qubit_gate_time: Some(100_000),
315 t_gate_time: Some(100_000),
316 one_qubit_measurement_error_rate: 1e-3,
317 one_qubit_gate_error_rate: 1e-3,
318 two_qubit_gate_error_rate: 1e-3,
319 t_gate_error_rate: 1e-6,
320 idle_error_rate: 1e-3,
321 }
322 }
323
324 #[must_use]
325 pub fn qubit_gate_us_e4() -> Self {
326 Self {
327 name: "qubit_gate_us_e4".into(),
328 one_qubit_measurement_time: Some(100_000),
329 one_qubit_gate_time: Some(100_000),
330 two_qubit_gate_time: Some(100_000),
331 t_gate_time: Some(100_000),
332 one_qubit_measurement_error_rate: 1e-4,
333 one_qubit_gate_error_rate: 1e-4,
334 two_qubit_gate_error_rate: 1e-4,
335 t_gate_error_rate: 1e-6,
336 idle_error_rate: 1e-4,
337 }
338 }
339
340 fn normalized(mut self) -> Result<Self, serde_json::error::Error> {
341 if let Some(default_model) = Self::from_default_name(&self.name) {
342 self.overwrite_from(&default_model);
343 }
344
345 // at this point we can assume that all values have been
346 // pre-assigned in case of pre-defined models
347 check_required_fields(&[
348 (
349 self.one_qubit_measurement_time.is_none(),
350 ONE_QUBIT_MEASUREMENT_TIME,
351 ),
352 (self.t_gate_error_rate.is_nan(), T_GATE_ERROR_RATE),
353 (
354 self.one_qubit_measurement_error_rate.is_nan(),
355 ONE_QUBIT_MEASUREMENT_ERROR_RATE,
356 ),
357 (self.one_qubit_gate_time.is_none(), ONE_QUBIT_GATE_TIME),
358 (
359 self.one_qubit_gate_error_rate.is_nan(),
360 ONE_QUBIT_GATE_ERROR_RATE,
361 ),
362 ])?;
363
364 // at this point we can assume that all required fields have been assigned
365 update_if_none(&mut self.two_qubit_gate_time, self.one_qubit_gate_time);
366 update_if_none(&mut self.t_gate_time, self.one_qubit_gate_time);
367 update_if_nan(
368 &mut self.two_qubit_gate_error_rate,
369 self.one_qubit_gate_error_rate,
370 );
371 update_if_nan(&mut self.t_gate_error_rate, self.one_qubit_gate_error_rate);
372 update_if_nan(
373 &mut self.idle_error_rate,
374 self.one_qubit_measurement_error_rate,
375 );
376
377 Ok(self)
378 }
379
380 fn overwrite_from(&mut self, base: &Self) {
381 update_if_none(
382 &mut self.one_qubit_measurement_time,
383 base.one_qubit_measurement_time,
384 );
385 update_if_none(&mut self.one_qubit_gate_time, base.one_qubit_gate_time);
386 update_if_none(&mut self.two_qubit_gate_time, base.two_qubit_gate_time);
387 update_if_none(&mut self.t_gate_time, base.t_gate_time);
388 update_if_nan(
389 &mut self.one_qubit_measurement_error_rate,
390 base.one_qubit_measurement_error_rate,
391 );
392 update_if_nan(
393 &mut self.one_qubit_gate_error_rate,
394 base.one_qubit_gate_error_rate,
395 );
396 update_if_nan(
397 &mut self.two_qubit_gate_error_rate,
398 base.two_qubit_gate_error_rate,
399 );
400 update_if_nan(&mut self.t_gate_error_rate, base.t_gate_error_rate);
401 update_if_nan(&mut self.idle_error_rate, base.idle_error_rate);
402 }
403}
404
405impl Default for GateBasedPhysicalQubit {
406 fn default() -> Self {
407 Self::qubit_gate_ns_e3()
408 }
409}
410
411impl MajoranaQubit {
412 fn from_default_name(name: &str) -> Option<Self> {
413 match name {
414 "qubit_maj_ns_e4" => Some(Self::qubit_maj_ns_e4()),
415 "qubit_maj_ns_e6" => Some(Self::qubit_maj_ns_e6()),
416 _ => None,
417 }
418 }
419
420 #[must_use]
421 pub fn qubit_maj_ns_e4() -> Self {
422 Self {
423 name: "qubit_maj_ns_e4".into(),
424 one_qubit_measurement_time: Some(100),
425 two_qubit_joint_measurement_time: Some(100),
426 t_gate_time: Some(100),
427 one_qubit_measurement_error_rate: MeasurementErrorRate::Detailed {
428 process: 1e-4,
429 readout: 1e-4,
430 },
431 two_qubit_joint_measurement_error_rate: MeasurementErrorRate::Detailed {
432 process: 1e-4,
433 readout: 1e-4,
434 },
435 t_gate_error_rate: 0.05,
436 idle_error_rate: 1e-4,
437 }
438 }
439
440 #[must_use]
441 pub fn qubit_maj_ns_e6() -> Self {
442 Self {
443 name: "qubit_maj_ns_e6".into(),
444 one_qubit_measurement_time: Some(100),
445 two_qubit_joint_measurement_time: Some(100),
446 t_gate_time: Some(100),
447 one_qubit_measurement_error_rate: MeasurementErrorRate::Detailed {
448 process: 1e-6,
449 readout: 1e-6,
450 },
451 two_qubit_joint_measurement_error_rate: MeasurementErrorRate::Detailed {
452 process: 1e-6,
453 readout: 1e-6,
454 },
455 t_gate_error_rate: 0.01,
456 idle_error_rate: 1e-6,
457 }
458 }
459
460 fn normalized(mut self) -> Result<Self, serde_json::error::Error> {
461 if let Some(default_model) = Self::from_default_name(&self.name) {
462 self.overwrite_from(&default_model);
463 }
464
465 // at this point we can assume that all values have been
466 // pre-assigned in case of pre-defined models
467 check_required_fields(&[
468 (
469 self.one_qubit_measurement_time.is_none(),
470 ONE_QUBIT_MEASUREMENT_TIME,
471 ),
472 (
473 self.one_qubit_measurement_error_rate.is_nan(),
474 ONE_QUBIT_MEASUREMENT_ERROR_RATE,
475 ),
476 (self.t_gate_error_rate.is_nan(), T_GATE_ERROR_RATE),
477 ])?;
478
479 // normalize error rates
480 let (_, readout_one) = self.one_qubit_measurement_error_rate.normalize();
481 let (process_two, readout_two) = self.two_qubit_joint_measurement_error_rate.normalize();
482
483 // at this point we can assume that all required fields have been assigned
484 update_if_none(
485 &mut self.two_qubit_joint_measurement_time,
486 self.one_qubit_measurement_time,
487 );
488 update_if_none(&mut self.t_gate_time, self.one_qubit_measurement_time);
489 update_if_nan(process_two, *readout_one);
490 update_if_nan(readout_two, *readout_one);
491 update_if_nan(&mut self.idle_error_rate, *readout_one);
492
493 Ok(self)
494 }
495
496 fn overwrite_from(&mut self, base: &Self) {
497 update_if_none(
498 &mut self.one_qubit_measurement_time,
499 base.one_qubit_measurement_time,
500 );
501 update_if_none(
502 &mut self.one_qubit_measurement_time,
503 base.one_qubit_measurement_time,
504 );
505 update_if_none(
506 &mut self.two_qubit_joint_measurement_time,
507 base.two_qubit_joint_measurement_time,
508 );
509 update_if_none(&mut self.t_gate_time, base.t_gate_time);
510
511 if self.one_qubit_measurement_error_rate.is_nan() {
512 self.one_qubit_measurement_error_rate = base.one_qubit_measurement_error_rate;
513 }
514 if self.two_qubit_joint_measurement_error_rate.is_nan() {
515 self.two_qubit_joint_measurement_error_rate =
516 base.two_qubit_joint_measurement_error_rate;
517 }
518
519 update_if_nan(&mut self.t_gate_error_rate, base.t_gate_error_rate);
520 update_if_nan(&mut self.idle_error_rate, base.idle_error_rate);
521 }
522}
523
524impl Default for MajoranaQubit {
525 fn default() -> Self {
526 Self::qubit_maj_ns_e4()
527 }
528}
529
530fn deserialize_error_rate<'de, D>(deserializer: D) -> Result<f64, D::Error>
531where
532 D: serde::Deserializer<'de>,
533{
534 let value: f64 = Deserialize::deserialize(deserializer)?;
535
536 if value <= 0.0 || value >= 1.0 {
537 Err(D::Error::custom("expected value between 0.0 and 1.0"))
538 } else {
539 Ok(value)
540 }
541}
542
543impl MeasurementErrorRate {
544 /// Normaizes the measurement error rate and returns the values for
545 /// process and readout
546 pub fn normalize(&mut self) -> (&mut f64, &mut f64) {
547 *self = match self {
548 Self::Simple(v) => Self::Detailed {
549 process: *v,
550 readout: *v,
551 },
552 Self::Detailed { process, readout } => Self::Detailed {
553 process: *process,
554 readout: *readout,
555 },
556 };
557
558 if let Self::Detailed { process, readout } = self {
559 (process, readout)
560 } else {
561 unreachable!()
562 }
563 }
564
565 pub fn is_nan(&self) -> bool {
566 match self {
567 Self::Simple(v) => v.is_nan(),
568 Self::Detailed { process, readout } => process.is_nan() && readout.is_nan(),
569 }
570 }
571
572 pub fn process(&self) -> f64 {
573 match *self {
574 Self::Simple(v) => v,
575 Self::Detailed { process, .. } => process,
576 }
577 }
578
579 pub fn readout(&self) -> f64 {
580 match *self {
581 Self::Simple(v) => v,
582 Self::Detailed { readout, .. } => readout,
583 }
584 }
585}
586
587impl Default for MeasurementErrorRate {
588 fn default() -> Self {
589 Self::Simple(f64::NAN)
590 }
591}
592
593#[inline]
594fn update_if_nan(value: &mut f64, base_value: f64) {
595 if value.is_nan() {
596 *value = base_value;
597 }
598}
599
600#[inline]
601fn update_if_none(value: &mut Option<u64>, base_value: Option<u64>) {
602 if value.is_none() {
603 *value = base_value;
604 }
605}
606