microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
7421e7dd1015dcbd940bf843d33583470de580ea

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/src/generic_estimator.rs

120lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use std::{rc::Rc, time::Instant};
5
6use pyo3::{prelude::*, types::PyDict};
7use resource_estimator::estimates::{ErrorBudget, ErrorBudgetStrategy, PhysicalResourceEstimation};
8use serde_json::json;
9
10use crate::generic_estimator::{
11 code::PythonQEC,
12 counts::PythonCounts,
13 factory::{PythonFactoryBuilder, PythonFactoryBuilderDispatch},
14 utils::json_map_to_python_dict,
15};
16
17mod code;
18mod counts;
19mod factory;
20mod utils;
21
22#[cfg(test)]
23mod tests;
24
25pub(crate) fn register_generic_estimator_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> {
26 m.add_function(wrap_pyfunction!(estimate_custom, m)?)?;
27 Ok(())
28}
29
30#[allow(clippy::too_many_arguments)]
31#[pyfunction]
32#[pyo3(
33 signature = (algorithm, qubit, qec, factories = vec![], *, error_budget = 0.01, max_factories = None, logical_depth_factor = None, max_physical_qubits = None, max_duration = None, error_budget_pruning = false),
34)]
35fn estimate_custom<'py>(
36 algorithm: Bound<'py, PyAny>,
37 qubit: Bound<'py, PyDict>,
38 qec: Bound<'py, PyAny>,
39 factories: Vec<Bound<'py, PyAny>>,
40 error_budget: f64,
41 max_factories: Option<u64>,
42 logical_depth_factor: Option<f64>,
43 max_physical_qubits: Option<u64>,
44 max_duration: Option<u64>,
45 error_budget_pruning: bool,
46) -> PyResult<Bound<'py, PyDict>> {
47 let error_budget = ErrorBudget::new(error_budget / 3.0, error_budget / 3.0, error_budget / 3.0);
48
49 // evaluate algorithm to compute post-mapping logical resource counts
50 let time_algorithm = Instant::now();
51 let algorithm_overhead = Rc::new(PythonCounts::from_bound(algorithm)?);
52 let time_algorithm = time_algorithm.elapsed().as_nanos();
53
54 // prepare estimation input
55 let qubit = Rc::new(qubit);
56 let code = PythonQEC::from_bound(qec)?;
57
58 // load factories from Python
59 let factories = factories
60 .into_iter()
61 .map(PythonFactoryBuilder::from_bound)
62 .collect::<PyResult<Vec<_>>>()?;
63
64 // create resource estimator
65 let mut estimation = PhysicalResourceEstimation::new(
66 code,
67 qubit.clone(),
68 PythonFactoryBuilderDispatch(factories),
69 algorithm_overhead.clone(),
70 );
71 if let Some(max_factories) = max_factories {
72 estimation.set_max_factories(max_factories);
73 }
74 if let Some(logical_depth_factor) = logical_depth_factor {
75 estimation.set_logical_depth_factor(logical_depth_factor);
76 }
77 if let Some(max_physical_qubits) = max_physical_qubits {
78 estimation.set_max_physical_qubits(max_physical_qubits);
79 }
80 if let Some(max_duration) = max_duration {
81 estimation.set_max_duration(max_duration);
82 }
83 if error_budget_pruning {
84 estimation.set_error_budget_strategy(ErrorBudgetStrategy::PruneLogicalAndRotations);
85 }
86
87 // perform estimation
88 let time_estimation = Instant::now();
89 let result = estimation
90 .estimate(&error_budget)
91 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
92 let time_estimation = time_estimation.elapsed().as_nanos();
93
94 // we first serialize the result to JSON, then convert it to a Python
95 // dictionary. The alternative would be to convert the result to a Python
96 // dictionary directly, but that would either:
97 // - require to ensure that all fields are consistently added to the result
98 // dictionary,
99 // - require to implement a custom serializer for a Python dictionary
100 let json = json!(&result);
101
102 // serialize the result to a Python dictionary and add some other fields
103 let dict = json_map_to_python_dict(
104 qubit.as_ref().py(),
105 json.as_object().expect("result is a JSON object"),
106 )?;
107
108 dict.set_item("qubit", qubit.as_ref())?;
109
110 if let Some(value) = algorithm_overhead.algorithm_overhead(&error_budget)? {
111 dict.set_item("algorithmOverhead", value)?;
112 }
113
114 let execution_stats = PyDict::new(qubit.as_ref().py());
115 execution_stats.set_item("timeAlgorithm", time_algorithm)?;
116 execution_stats.set_item("timeEstimation", time_estimation)?;
117 dict.set_item("executionStats", execution_stats)?;
118
119 Ok(dict)
120}
121