microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.18.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/src/generic_estimator/factory/round_based.rs

199lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use std::cmp::Ordering;
5
6use pyo3::{
7 types::{PyAnyMethods, PyDict},
8 Bound, PyResult,
9};
10use resource_estimator::estimates::DistillationUnit;
11
12use super::super::utils::SerializableBound;
13
14/// A wrapper to model a distillation unit for round-based factory builders.
15pub struct PythonDistillationUnit<'py> {
16 dict: Bound<'py, PyDict>,
17 name: String,
18 code_parameter: Option<SerializableBound<'py>>,
19}
20
21impl<'py> PythonDistillationUnit<'py> {
22 pub fn new(dict: Bound<'py, PyDict>) -> PyResult<Self> {
23 let name = dict.get_item("name").map_or_else(
24 |_| Ok(String::from("distillation-unit")),
25 |field| -> PyResult<String> { Ok(field.to_string()) },
26 )?;
27
28 let code_parameter = dict.get_item("code_parameter").map_or(
29 Ok(None),
30 |field| -> PyResult<Option<SerializableBound<'py>>> {
31 if field.is_none() {
32 Ok(None)
33 } else {
34 Ok(Some(SerializableBound(field)))
35 }
36 },
37 )?;
38
39 Ok(Self {
40 dict,
41 name,
42 code_parameter,
43 })
44 }
45}
46
47impl<'py> DistillationUnit<SerializableBound<'py>> for PythonDistillationUnit<'py> {
48 fn num_output_states(&self) -> u64 {
49 let Ok(field) = self.dict.get_item("num_output_states") else {
50 return 1;
51 };
52
53 field
54 .extract()
55 .expect("can extract u64 value from field num_output_states")
56 }
57
58 fn num_input_states(&self) -> u64 {
59 self.dict
60 .get_item("num_input_states")
61 .expect("has field num_input_states")
62 .extract()
63 .expect("can extract u64 value from field num_input_states")
64 }
65
66 fn duration(&self, position: usize) -> u64 {
67 self.dict
68 .get_item("duration")
69 .expect("has field duration")
70 .call1((position,))
71 .expect("can call lambda duration")
72 .extract()
73 .expect("can extract u64 value from lambda duration")
74 }
75
76 fn physical_qubits(&self, position: usize) -> u64 {
77 self.dict
78 .get_item("physical_qubits")
79 .expect("has field physical_qubits")
80 .call1((position,))
81 .expect("can call lambda physical_qubits")
82 .extract()
83 .expect("can extract u64 value from lambda physical_qubits")
84 }
85
86 fn name(&self) -> &str {
87 &self.name
88 }
89
90 fn code_parameter(&self) -> Option<&SerializableBound<'py>> {
91 self.code_parameter.as_ref()
92 }
93
94 fn output_error_rate(&self, input_error_rate: f64) -> f64 {
95 self.dict
96 .get_item("output_error_rate")
97 .expect("has field output_error_rate")
98 .call1((input_error_rate,))
99 .expect("can call lambda output_error_rate")
100 .extract()
101 .expect("can extract u64 value from lambda output_error_rate")
102 }
103
104 fn failure_probability(&self, input_error_rate: f64) -> f64 {
105 self.dict
106 .get_item("failure_probability")
107 .expect("has field failure_probability")
108 .call1((input_error_rate,))
109 .expect("can call lambda failure_probability")
110 .extract()
111 .expect("can extract u64 value from lambda failure_probability")
112 }
113}
114
115impl PartialEq for PythonDistillationUnit<'_> {
116 fn eq(&self, other: &Self) -> bool {
117 match (self.code_parameter(), other.code_parameter()) {
118 (Some(lhs), Some(rhs)) => {
119 let Ok(eq_fun) = lhs.getattr("__eq__") else {
120 return false;
121 };
122 let Ok(eq_result) = eq_fun.call1((&**rhs,)) else {
123 return false;
124 };
125
126 eq_result.extract().unwrap_or(false)
127 }
128 (None, None) => true,
129 _ => false,
130 }
131 }
132}
133
134impl PartialOrd for PythonDistillationUnit<'_> {
135 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
136 let lhs = self.code_parameter()?;
137 let rhs = other.code_parameter()?;
138
139 let eq_fun = lhs.getattr("__eq__").ok()?;
140 if eq_fun.call1((&**rhs,)).ok()?.extract().ok()? {
141 return Some(Ordering::Equal);
142 }
143
144 let lt_fun = lhs.getattr("__lt__").ok()?;
145 if lt_fun.call1((&**rhs,)).ok()?.extract().ok()? {
146 Some(Ordering::Less)
147 } else {
148 Some(Ordering::Greater)
149 }
150 }
151}
152
153pub enum OrderedBFSControl {
154 Continue,
155 #[allow(dead_code)]
156 Cutoff,
157 Terminate,
158}
159
160/// Performs a breadth-first search (BFS) over the elements with up to
161/// `max_depth` repetitions. It is guaranteed that the elements remain in the
162/// same order as initially provided. The function `visit` is called on each
163/// tuple.
164pub fn ordered_bfs<T: PartialOrd>(
165 elements: &[T],
166 max_depth: usize,
167 mut visit: impl FnMut(Vec<&T>) -> Result<OrderedBFSControl, String>,
168) -> Result<(), String> {
169 let mut prev_prefixes = vec![vec![]];
170
171 for _ in 1..=max_depth {
172 let mut prefixes = vec![];
173
174 for stem in &prev_prefixes {
175 for (idx, element) in elements.iter().enumerate() {
176 if stem.last().is_some_and(|last| *element < elements[*last]) {
177 continue;
178 }
179
180 let mut new_tuple = stem.clone();
181 new_tuple.push(idx);
182
183 match visit(new_tuple.iter().copied().map(|i| &elements[i]).collect())? {
184 OrderedBFSControl::Continue => {
185 prefixes.push(new_tuple);
186 }
187 OrderedBFSControl::Cutoff => {}
188 OrderedBFSControl::Terminate => {
189 return Ok(());
190 }
191 }
192 }
193 }
194
195 prev_prefixes = prefixes;
196 }
197
198 Ok(())
199}
200