Skip to content

Commit

Permalink
Serialize logical post-layout overhead in resource estimation result (#…
Browse files Browse the repository at this point in the history
…1914)

This change allows to serialize the logical post-layout overhead in the
resource estimation result provided by the resource estimation API. Note
that this was already possible in the system API that has a custom
result for the VS Code and Python integration.

The change also simplified the type of the resource estimation result,
which now is not any longer generic over the post-layout overhead trait.
  • Loading branch information
msoeken authored Sep 16, 2024
1 parent 5d193f4 commit 7b532fe
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 90 deletions.
2 changes: 1 addition & 1 deletion resource_estimator/src/estimates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ pub use physical_estimation::{
};
mod layout;
mod logical_qubit;
pub use layout::Overhead;
pub use layout::{Overhead, RealizedOverhead};
pub use logical_qubit::LogicalPatch;
pub mod optimization;
65 changes: 65 additions & 0 deletions resource_estimator/src/estimates/layout.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use serde::Serialize;

use super::ErrorBudget;

/// Trait to model post-layout logical overhead
Expand All @@ -22,3 +24,66 @@ pub trait Overhead {
/// supported by available factory builders in the physical estimation.
fn num_magic_states(&self, budget: &ErrorBudget, index: usize) -> u64;
}

/// This is the realized logical overhead after applying an error budget. This
/// structure has two purposes: 1) it is used to store the realized logical
/// overhead, once the error budget partition is decided into the resource
/// estimation result; 2) it can be used to pass a logical overhead to the
/// resource estimation API, if it does not depend on the error budget, since it
/// also implements the [`Overhead`] trait.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RealizedOverhead {
logical_qubits: u64,
logical_depth: u64,
num_magic_states: Vec<u64>,
}

impl RealizedOverhead {
pub fn from_overhead(
overhead: &impl Overhead,
budget: &ErrorBudget,
num_magic_state_types: usize,
) -> Self {
let logical_qubits = overhead.logical_qubits();
let logical_depth = overhead.logical_depth(budget);
let num_magic_states = (0..num_magic_state_types)
.map(|index| overhead.num_magic_states(budget, index))
.collect();

Self {
logical_qubits,
logical_depth,
num_magic_states,
}
}

#[must_use]
pub fn logical_qubits(&self) -> u64 {
self.logical_qubits
}

#[must_use]
pub fn logical_depth(&self) -> u64 {
self.logical_depth
}

#[must_use]
pub fn num_magic_states(&self) -> &[u64] {
&self.num_magic_states
}
}

impl Overhead for RealizedOverhead {
fn logical_qubits(&self) -> u64 {
self.logical_qubits
}

fn logical_depth(&self, _budget: &ErrorBudget) -> u64 {
self.logical_depth
}

fn num_magic_states(&self, _budget: &ErrorBudget, index: usize) -> u64 {
self.num_magic_states[index]
}
}
26 changes: 16 additions & 10 deletions resource_estimator/src/estimates/physical_estimation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ impl<
}
}

pub fn error_correction(&self) -> &E {
&self.ftp
}

pub fn layout_overhead(&self) -> &L {
&self.layout_overhead
}
Expand All @@ -274,13 +278,15 @@ impl<
self.max_physical_qubits = Some(max_physical_qubits);
}

pub fn factory_builder(&self) -> &Builder {
&self.factory_builder
}

pub fn factory_builder_mut(&mut self) -> &mut Builder {
&mut self.factory_builder
}

pub fn estimate(
&self,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
pub fn estimate(&self) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
match (self.max_duration, self.max_physical_qubits) {
(None, None) => self.estimate_without_restrictions(),
(None, Some(max_physical_qubits)) => {
Expand All @@ -294,7 +300,7 @@ impl<
#[allow(clippy::too_many_lines, clippy::type_complexity)]
pub fn build_frontier(
&self,
) -> Result<Vec<PhysicalResourceEstimationResult<E, Builder::Factory, L>>, Error> {
) -> Result<Vec<PhysicalResourceEstimationResult<E, Builder::Factory>>, Error> {
if self.factory_builder.num_magic_state_types() != 1 {
return Err(Error::MultipleMagicStatesNotSupported);
}
Expand Down Expand Up @@ -329,7 +335,7 @@ impl<
}

let mut best_estimation_results =
Population::<Point2D<PhysicalResourceEstimationResult<E, Builder::Factory, L>>>::new();
Population::<Point2D<PhysicalResourceEstimationResult<E, Builder::Factory>>>::new();

let mut last_factories = Vec::new();
let mut last_code_parameter = None;
Expand Down Expand Up @@ -455,7 +461,7 @@ impl<

pub fn estimate_without_restrictions(
&self,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
let mut num_cycles = self.compute_num_cycles()?;

loop {
Expand Down Expand Up @@ -616,7 +622,7 @@ impl<
pub fn estimate_with_max_duration(
&self,
max_duration_in_nanoseconds: u64,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
if self.factory_builder.num_magic_state_types() != 1 {
return Err(Error::MultipleMagicStatesNotSupported);
}
Expand Down Expand Up @@ -647,7 +653,7 @@ impl<
}

let mut best_estimation_result: Option<
PhysicalResourceEstimationResult<E, Builder::Factory, L>,
PhysicalResourceEstimationResult<E, Builder::Factory>,
> = None;

let mut last_factories = Vec::new();
Expand Down Expand Up @@ -767,7 +773,7 @@ impl<
pub fn estimate_with_max_num_qubits(
&self,
max_num_qubits: u64,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
if self.factory_builder.num_magic_state_types() != 1 {
return Err(Error::MultipleMagicStatesNotSupported);
}
Expand Down Expand Up @@ -795,7 +801,7 @@ impl<
}

let mut best_estimation_result: Option<
PhysicalResourceEstimationResult<E, Builder::Factory, L>,
PhysicalResourceEstimationResult<E, Builder::Factory>,
> = None;

let mut last_factories = Vec::new();
Expand Down
41 changes: 23 additions & 18 deletions resource_estimator/src/estimates/physical_estimation/result.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use std::rc::Rc;

use serde::Serialize;

use crate::estimates::{
ErrorBudget, ErrorCorrection, Factory, FactoryBuilder, LogicalPatch, Overhead,
PhysicalResourceEstimation,
PhysicalResourceEstimation, RealizedOverhead,
};

/// Resource estimation result
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PhysicalResourceEstimationResult<E: ErrorCorrection, F, L> {
pub struct PhysicalResourceEstimationResult<E: ErrorCorrection, F> {
#[serde(bound = "E::Parameter: Serialize")]
logical_patch: LogicalPatch<E>,
num_cycles: u64,
Expand All @@ -25,19 +23,19 @@ pub struct PhysicalResourceEstimationResult<E: ErrorCorrection, F, L> {
physical_qubits: u64,
runtime: u64,
rqops: u64,
#[serde(skip)]
layout_overhead: Rc<L>,
layout_overhead: RealizedOverhead,
error_budget: ErrorBudget,
}

impl<
E: ErrorCorrection<Parameter = impl Clone>,
F: Factory<Parameter = E::Parameter> + Clone,
L: Overhead,
> PhysicalResourceEstimationResult<E, F, L>
impl<E: ErrorCorrection<Parameter = impl Clone>, F: Factory<Parameter = E::Parameter> + Clone>
PhysicalResourceEstimationResult<E, F>
{
pub fn new(
estimation: &PhysicalResourceEstimation<E, impl FactoryBuilder<E, Factory = F>, L>,
estimation: &PhysicalResourceEstimation<
E,
impl FactoryBuilder<E, Factory = F>,
impl Overhead,
>,
logical_patch: LogicalPatch<E>,
num_cycles: u64,
factory_parts: Vec<Option<FactoryPart<F>>>,
Expand Down Expand Up @@ -71,13 +69,21 @@ impl<
physical_qubits,
runtime,
rqops,
layout_overhead: estimation.layout_overhead.clone(),
layout_overhead: RealizedOverhead::from_overhead(
estimation.layout_overhead(),
estimation.error_budget(),
estimation.factory_builder().num_magic_state_types(),
),
error_budget: estimation.error_budget().clone(),
}
}

pub fn without_factories(
estimation: &PhysicalResourceEstimation<E, impl FactoryBuilder<E, Factory = F>, L>,
estimation: &PhysicalResourceEstimation<
E,
impl FactoryBuilder<E, Factory = F>,
impl Overhead,
>,
logical_patch: LogicalPatch<E>,
num_cycles: u64,
required_logical_patch_error_rate: f64,
Expand Down Expand Up @@ -136,7 +142,7 @@ impl<
self.rqops
}

pub fn layout_overhead(&self) -> &Rc<L> {
pub fn layout_overhead(&self) -> &RealizedOverhead {
&self.layout_overhead
}

Expand All @@ -145,14 +151,13 @@ impl<
}

pub fn algorithmic_logical_depth(&self) -> u64 {
self.layout_overhead.logical_depth(&self.error_budget)
self.layout_overhead.logical_depth()
}

/// The argument index indicates for which type of magic state (starting
/// from 0) the number is requested for.
pub fn num_magic_states(&self, index: usize) -> u64 {
self.layout_overhead
.num_magic_states(&self.error_budget, index)
self.layout_overhead.num_magic_states()[index]
}
}

Expand Down
11 changes: 8 additions & 3 deletions resource_estimator/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,16 @@ fn estimate_single<L: Overhead + LayoutReportData + PartitioningOverhead + Seria
.error_budget()
.partitioning(logical_resources.as_ref())?;

// The clone on the logical resources is on an Rc and therefore inexpensive,
// the value is later used in creating the result object
let mut estimation = PhysicalResourceEstimation::new(
ftp,
qubit,
TFactoryBuilder::new(
distillation_unit_templates,
job_params.constraints().max_distillation_rounds,
),
logical_resources,
logical_resources.clone(),
partitioning,
);
if let Some(logical_depth_factor) = job_params.constraints().logical_depth_factor {
Expand Down Expand Up @@ -126,11 +128,14 @@ fn estimate_single<L: Overhead + LayoutReportData + PartitioningOverhead + Seria
let estimation_result = estimation
.build_frontier()
.map_err(std::convert::Into::into);
estimation_result.map(|result| data::Success::new_from_multiple(job_params, result))
estimation_result.map(|result| {
data::Success::new_from_multiple(job_params, logical_resources, result)
})
}
EstimateType::SinglePoint => {
let estimation_result = estimation.estimate().map_err(std::convert::Into::into);
estimation_result.map(|result| data::Success::new(job_params, result))
estimation_result
.map(|result| data::Success::new(job_params, logical_resources, result))
}
}
}
Expand Down
35 changes: 14 additions & 21 deletions resource_estimator/src/system/data/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod tests;

use serde::Serialize;

use crate::estimates::{Factory, FactoryPart, Overhead, PhysicalResourceEstimationResult};
use crate::estimates::{Factory, FactoryPart, PhysicalResourceEstimationResult};
use crate::system::modeling::Protocol;

use super::LayoutReportData;
Expand All @@ -28,14 +28,11 @@ impl Report {
#[allow(clippy::vec_init_then_push, clippy::too_many_lines)]
pub fn new(
job_params: &JobParams,
result: &PhysicalResourceEstimationResult<
Protocol,
TFactory,
impl Overhead + LayoutReportData,
>,
layout_report_data: &impl LayoutReportData,
result: &PhysicalResourceEstimationResult<Protocol, TFactory>,
formatted_counts: &FormattedPhysicalResourceCounts,
) -> Self {
let logical_counts = result.layout_overhead();
let logical_counts = layout_report_data;
// In this system, we consider T as the only magic state type, therefore
// there is only one factory part in the result.
let part = result.factory_parts()[0].as_ref();
Expand Down Expand Up @@ -363,12 +360,9 @@ pub struct FormattedPhysicalResourceCounts {
impl FormattedPhysicalResourceCounts {
#[allow(clippy::too_many_lines)]
pub fn new(
result: &PhysicalResourceEstimationResult<
Protocol,
TFactory,
impl Overhead + LayoutReportData,
>,
result: &PhysicalResourceEstimationResult<Protocol, TFactory>,
job_params: &JobParams,
layout_report_data: &impl LayoutReportData,
) -> Self {
// Physical resource estimates
let runtime = format_duration(result.runtime().into());
Expand Down Expand Up @@ -474,25 +468,24 @@ impl FormattedPhysicalResourceCounts {
});

// Pre-layout logical resources
let logical_counts_num_qubits = format_metric_prefix(result.layout_overhead().num_qubits());
let logical_counts_t_count = format_metric_prefix(result.layout_overhead().t_count());
let logical_counts_num_qubits = format_metric_prefix(layout_report_data.num_qubits());
let logical_counts_t_count = format_metric_prefix(layout_report_data.t_count());
let logical_counts_rotation_count =
format_metric_prefix(result.layout_overhead().rotation_count());
format_metric_prefix(layout_report_data.rotation_count());
let logical_counts_rotation_depth =
format_metric_prefix(result.layout_overhead().rotation_depth());
let logical_counts_ccz_count = format_metric_prefix(result.layout_overhead().ccz_count());
let logical_counts_ccix_count = format_metric_prefix(result.layout_overhead().ccix_count());
format_metric_prefix(layout_report_data.rotation_depth());
let logical_counts_ccz_count = format_metric_prefix(layout_report_data.ccz_count());
let logical_counts_ccix_count = format_metric_prefix(layout_report_data.ccix_count());
let logical_counts_measurement_count =
format_metric_prefix(result.layout_overhead().measurement_count());
format_metric_prefix(layout_report_data.measurement_count());

// Assumed error budget
let error_budget = format!("{:.2e}", job_params.error_budget().total());
let error_budget_logical = format!("{:.2e}", result.error_budget().logical());
let error_budget_tstates = format!("{:.2e}", result.error_budget().magic_states());
let error_budget_rotations = format!("{:.2e}", result.error_budget().rotations());

let num_ts_per_rotation = result
.layout_overhead()
let num_ts_per_rotation = layout_report_data
.num_ts_per_rotation(result.error_budget().rotations())
.map_or_else(|| String::from(no_rotations_msg), format_metric_prefix);

Expand Down
Loading

0 comments on commit 7b532fe

Please sign in to comment.