microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/qdk_package

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/src/generic_estimator/counts.rs

136lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use pyo3::{
5 Bound, PyAny, PyResult,
6 types::{PyAnyMethods, PyDict},
7};
8use resource_estimator::estimates::{ErrorBudget, Overhead};
9
10use super::utils::extract_and_check_method;
11
12/// A wrapper around a Python instance to compute post-layout logical overhead
13/// for generic resource estimation.
14///
15/// The Python instance must implement three methods to compute the number of
16/// logical qubits, the logical depth, and the number of magic states. For the
17/// last two methods, the method receives a parameter `budget`, which is a
18/// dictionary with access to the chosen error budget for logical errors
19/// (`"logical"`), rotation synthesis budget (`"rotations"`), and magic state
20/// budget (`"magic_states"`):
21///
22/// ```python
23/// def logical_qubits(self):
24/// # must return an int
25/// ...
26///
27/// def logical_depth(self, budget):
28/// # must return an int
29/// #
30/// # budget is a dictionary of the form
31/// # {"logical": ..., "rotations": ..., "magic_states": ...}
32/// ...
33///
34/// def num_magic_states(self, budget, index):
35/// # must return an int
36/// #
37/// # here index is the type of magic state; normally this number is 0,
38/// # as there is only one magic state, but if there are multiple, this
39/// # is some number starting from 0.
40/// ...
41/// ```
42///
43/// It's important to note that the number of factory builders provided in the
44/// `estimate_generic` function determine how many magic states are being
45/// requested from the logical counts model. If only one factory is provided,
46/// then the `num_magic_states` method is only requested for the index `0` and
47/// not for any other indices.
48///
49/// Optionally, the instance may implement a method called `algorithm_overhead`,
50/// which also takes the error budget parameter `parameter` and returns a Python
51/// dictionary that is serialized into the estimation result, accessible via the
52/// key `"algorithmOverhead"`. This can contain layout-specific variables that
53/// are interesting statistics to expose.
54///
55/// ```python
56/// def algorithm_overhead(self, budget):
57/// # returns a serializable Python dictionary
58/// ...
59/// ```
60pub struct PythonCounts<'py> {
61 counts: Bound<'py, PyAny>,
62 logical_qubits_method: Bound<'py, PyAny>,
63 logical_depth_method: Bound<'py, PyAny>,
64 num_magic_states_method: Bound<'py, PyAny>,
65}
66
67impl<'py> PythonCounts<'py> {
68 pub fn from_bound(counts: Bound<'py, PyAny>) -> PyResult<Self> {
69 let logical_qubits_method = extract_and_check_method(&counts, "logical_qubits")?;
70 let logical_depth_method = extract_and_check_method(&counts, "logical_depth")?;
71 let num_magic_states_method = extract_and_check_method(&counts, "num_magic_states")?;
72
73 Ok(Self {
74 counts,
75 logical_qubits_method,
76 logical_depth_method,
77 num_magic_states_method,
78 })
79 }
80
81 fn convert_budget(&self, budget: &ErrorBudget) -> PyResult<Bound<'py, PyDict>> {
82 let dict = PyDict::new(self.counts.py());
83
84 dict.set_item("logical", budget.logical())?;
85 dict.set_item("rotations", budget.rotations())?;
86 dict.set_item("magic_states", budget.magic_states())?;
87
88 Ok(dict)
89 }
90
91 pub fn algorithm_overhead(
92 &self,
93 error_budget: &ErrorBudget,
94 ) -> PyResult<Option<Bound<'py, PyAny>>> {
95 if let Ok(result) = self
96 .counts
97 .getattr("algorithm_overhead")
98 .and_then(|f| f.call1((self.convert_budget(error_budget)?,)))
99 {
100 Ok(Some(result))
101 } else {
102 Ok(None)
103 }
104 }
105}
106
107impl Overhead for PythonCounts<'_> {
108 fn logical_qubits(&self) -> Result<u64, String> {
109 let result = self
110 .logical_qubits_method
111 .call0()
112 .map_err(|e| e.to_string())?;
113 result.extract().map_err(|e| e.to_string())
114 }
115
116 fn logical_depth(&self, budget: &ErrorBudget) -> Result<u64, String> {
117 let budget = self.convert_budget(budget).map_err(|e| e.to_string())?;
118
119 let result = self
120 .logical_depth_method
121 .call1((budget,))
122 .map_err(|e| e.to_string())?;
123
124 result.extract().map_err(|e| e.to_string())
125 }
126
127 fn num_magic_states(&self, budget: &ErrorBudget, index: usize) -> Result<u64, String> {
128 let budget = self.convert_budget(budget).map_err(|e| e.to_string())?;
129 let result = self
130 .num_magic_states_method
131 .call1((budget, index))
132 .map_err(|e| e.to_string())?;
133
134 result.extract().map_err(|e| e.to_string())
135 }
136}
137