microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/openqasm-extern-compilation

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/resource_estimator/src/system/data/result.rs

285lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use std::ops::Deref;
5use std::rc::Rc;
6
7use crate::estimates::{ErrorBudget, FactoryPart, LogicalPatch, PhysicalResourceEstimationResult};
8use crate::system::modeling::{Protocol, TFactory};
9
10use super::LayoutReportData;
11use super::{
12 super::Error, FormattedPhysicalResourceCounts, JobParams, PhysicalResourceCounts,
13 PhysicalResourceCountsBreakdown, Report,
14};
15use miette::Diagnostic;
16use serde::{Serialize, Serializer, ser::SerializeMap};
17
18#[derive(Serialize)]
19#[serde(rename_all(serialize = "camelCase"))]
20pub struct Success<L: LayoutReportData + Serialize> {
21 status: &'static str,
22 job_params: JobParams,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 physical_counts: Option<PhysicalResourceCounts>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 physical_counts_formatted: Option<FormattedPhysicalResourceCounts>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 logical_qubit: Option<LogicalQubit>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 tfactory: Option<TFactory>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 error_budget: Option<ErrorBudget>,
33 logical_counts: Rc<L>,
34 report_data: Report,
35 #[serde(skip_serializing_if = "Vec::is_empty")]
36 frontier_entries: Vec<FrontierEntry>,
37}
38
39impl<L: LayoutReportData + Serialize> Success<L> {
40 pub fn new(
41 job_params: JobParams,
42 layout_report_data: Rc<L>,
43 result: PhysicalResourceEstimationResult<Protocol, TFactory>,
44 ) -> Self {
45 let counts = create_physical_resource_counts(&result, layout_report_data.as_ref());
46
47 let formatted_counts: FormattedPhysicalResourceCounts =
48 FormattedPhysicalResourceCounts::new(&result, &job_params, layout_report_data.as_ref());
49
50 let report_data = Report::new(
51 &job_params,
52 layout_report_data.as_ref(),
53 &result,
54 &formatted_counts,
55 );
56
57 let (logical_qubit, mut parts, error_budget) = result.take();
58 let tfactory = parts.swap_remove(0).map(FactoryPart::into_factory);
59
60 Self {
61 status: "success",
62 job_params,
63 physical_counts: Some(counts),
64 physical_counts_formatted: Some(formatted_counts),
65 logical_qubit: Some(LogicalQubit(logical_qubit)),
66 tfactory,
67 error_budget: Some(error_budget),
68 logical_counts: layout_report_data,
69 report_data,
70 frontier_entries: Vec::new(),
71 }
72 }
73
74 pub fn new_from_multiple(
75 job_params: JobParams,
76 layout_report_data: Rc<L>,
77 mut results: Vec<PhysicalResourceEstimationResult<Protocol, TFactory>>,
78 ) -> Self {
79 let mut report_data: Option<Report> = None;
80
81 let mut frontier_entries: Vec<FrontierEntry> = Vec::new();
82
83 // we will pick the shortest runtime result as the first result.
84 results.sort_by_key(PhysicalResourceEstimationResult::runtime);
85 for result in results {
86 let (frontier_entry, report) = create_frontier_entry(
87 &job_params,
88 result,
89 layout_report_data.as_ref(),
90 report_data.is_none(),
91 );
92
93 if report_data.is_none() {
94 report_data = Some(report.expect("error should have report"));
95 }
96
97 frontier_entries.push(frontier_entry);
98 }
99
100 Self {
101 status: "success",
102 job_params,
103 physical_counts: None,
104 physical_counts_formatted: None,
105 logical_qubit: None,
106 tfactory: None,
107 error_budget: None,
108 logical_counts: layout_report_data,
109 report_data: report_data.expect("error should have report"), // Here we assume that at least a single solution was found.
110 frontier_entries,
111 }
112 }
113}
114
115#[derive(Serialize)]
116#[serde(rename_all(serialize = "camelCase"))]
117pub struct FrontierEntry {
118 pub logical_qubit: LogicalQubit,
119 pub tfactory: Option<TFactory>,
120 pub error_budget: ErrorBudget,
121 pub physical_counts: PhysicalResourceCounts,
122 pub physical_counts_formatted: FormattedPhysicalResourceCounts,
123}
124
125fn create_frontier_entry(
126 job_params: &JobParams,
127 result: PhysicalResourceEstimationResult<Protocol, TFactory>,
128 layout_report_data: &impl LayoutReportData,
129 create_report: bool,
130) -> (FrontierEntry, Option<Report>) {
131 let physical_counts = create_physical_resource_counts(&result, layout_report_data);
132
133 let physical_counts_formatted: FormattedPhysicalResourceCounts =
134 FormattedPhysicalResourceCounts::new(&result, job_params, layout_report_data);
135
136 let report_data = if create_report {
137 Some(Report::new(
138 job_params,
139 layout_report_data,
140 &result,
141 &physical_counts_formatted,
142 ))
143 } else {
144 None
145 };
146
147 let (logical_qubit, mut parts, error_budget) = result.take();
148 let tfactory = parts.swap_remove(0).map(FactoryPart::into_factory);
149
150 (
151 FrontierEntry {
152 logical_qubit: LogicalQubit(logical_qubit),
153 tfactory,
154 error_budget,
155 physical_counts,
156 physical_counts_formatted,
157 },
158 report_data,
159 )
160}
161
162fn create_physical_resource_counts(
163 result: &PhysicalResourceEstimationResult<Protocol, TFactory>,
164 layout_report_data: &impl LayoutReportData,
165) -> PhysicalResourceCounts {
166 let breakdown = create_physical_resource_counts_breakdown(result, layout_report_data);
167
168 PhysicalResourceCounts {
169 physical_qubits: result.physical_qubits(),
170 runtime: result.runtime(),
171 rqops: result.rqops(),
172 breakdown,
173 }
174}
175
176fn create_physical_resource_counts_breakdown(
177 result: &PhysicalResourceEstimationResult<Protocol, TFactory>,
178 layout_report_data: &impl LayoutReportData,
179) -> PhysicalResourceCountsBreakdown {
180 let num_ts_per_rotation =
181 layout_report_data.num_ts_per_rotation(result.error_budget().rotations());
182
183 let part = result.factory_parts()[0].as_ref();
184
185 PhysicalResourceCountsBreakdown {
186 algorithmic_logical_qubits: result.layout_overhead().logical_qubits(),
187 algorithmic_logical_depth: result.layout_overhead().logical_depth(),
188 logical_depth: result.num_cycles(),
189 clock_frequency: result.logical_patch().logical_cycles_per_second(),
190 num_tstates: result.layout_overhead().num_magic_states()[0],
191 num_tfactories: part.map_or(0, FactoryPart::copies),
192 num_tfactory_runs: part.map_or(0, FactoryPart::runs),
193 physical_qubits_for_tfactories: result.physical_qubits_for_factories(),
194 physical_qubits_for_algorithm: result.physical_qubits_for_algorithm(),
195 required_logical_qubit_error_rate: result.required_logical_error_rate(),
196 required_logical_tstate_error_rate: part.map(FactoryPart::required_output_error_rate),
197 num_ts_per_rotation,
198 clifford_error_rate: result
199 .logical_patch()
200 .physical_qubit()
201 .clifford_error_rate(),
202 }
203}
204
205pub struct Failure {
206 error: Error,
207 batch_index: Option<usize>,
208}
209
210impl Failure {
211 #[must_use]
212 pub fn new(error: Error) -> Self {
213 Self {
214 error,
215 batch_index: None,
216 }
217 }
218}
219
220impl Serialize for Failure {
221 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
222 where
223 S: Serializer,
224 {
225 let mut map = serializer.serialize_map(Some(4))?;
226
227 map.serialize_entry(
228 "code",
229 &self
230 .error
231 .code()
232 .expect("error should have code")
233 .to_string(),
234 )?;
235 if let Some(batch_index) = self.batch_index {
236 map.serialize_entry(
237 "message",
238 &format!("[batch index {}] {:?}", batch_index, self.error),
239 )?;
240 } else {
241 map.serialize_entry("message", &self.error.to_string())?;
242 }
243
244 map.end()
245 }
246}
247
248/// A helper newtype to specialize serialization for `LogicalPatch<Protocol>`
249pub struct LogicalQubit(LogicalPatch<Protocol>);
250
251impl Deref for LogicalQubit {
252 type Target = LogicalPatch<Protocol>;
253
254 fn deref(&self) -> &Self::Target {
255 &self.0
256 }
257}
258
259impl Serialize for LogicalQubit {
260 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
261 where
262 S: Serializer,
263 {
264 let mut map = serializer.serialize_map(Some(4))?;
265 map.serialize_entry("codeDistance", &self.code_parameter())?;
266 map.serialize_entry("physicalQubits", &self.physical_qubits())?;
267 map.serialize_entry("logicalCycleTime", &self.logical_cycle_time())?;
268 map.serialize_entry("logicalErrorRate", &self.logical_error_rate())?;
269
270 map.end()
271 }
272}
273
274impl Serialize for ErrorBudget {
275 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
276 where
277 S: Serializer,
278 {
279 let mut map = serializer.serialize_map(Some(3))?;
280 map.serialize_entry("logical", &self.logical())?;
281 map.serialize_entry("tstates", &self.magic_states())?;
282 map.serialize_entry("rotations", &self.rotations())?;
283 map.end()
284 }
285}
286