Skip to content

Commit 15c26c4

Browse files
authored
Multiple magic states and factory types (#1287)
This PR - simplifies the `Overhead` trait by requiring information about the number of magic states per rotation (moved to implementation) - allows to specify an index for the type of magic state (both in `Overhead` and in `FactoryBuilder` to determine how many different magic states are provided) - changes the return type of `FactoryBuilder::find_factories` to return `Vec<Cow<Factory>>` instead of `Vec<Factory>` such that implementors do not need to copy factories in case they are already pre-computed - adds helper structs to pass no factories or to merge two separate factories to produce a factory builder that produces two different magic states
1 parent 06f1fa5 commit 15c26c4

File tree

21 files changed

+713
-498
lines changed

21 files changed

+713
-498
lines changed

resource_estimator/src/counts.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,14 +577,17 @@ pub struct LayerInfo {
577577
}
578578

579579
impl LayerInfo {
580+
#[must_use]
580581
pub fn new_with_t() -> Self {
581582
Self { t: 1, r: 0, ccz: 0 }
582583
}
583584

585+
#[must_use]
584586
pub fn new_with_r() -> Self {
585587
Self { t: 0, r: 1, ccz: 0 }
586588
}
587589

590+
#[must_use]
588591
pub fn new_with_ccz() -> Self {
589592
Self { t: 0, r: 0, ccz: 1 }
590593
}

resource_estimator/src/estimates.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ pub use error::Error;
66
mod error_budget;
77
pub use error_budget::ErrorBudget;
88
mod factory;
9-
pub use factory::{DistillationRound, DistillationUnit, FactoryBuildError, RoundBasedFactory};
9+
pub use factory::{
10+
BuilderDispatch2, DistillationRound, DistillationUnit, FactoryBuildError, FactoryDispatch2,
11+
NoFactories, RoundBasedFactory,
12+
};
1013
mod physical_estimation;
1114
pub use physical_estimation::{
12-
ErrorCorrection, Factory, FactoryBuilder, PhysicalResourceEstimation,
15+
ErrorCorrection, Factory, FactoryBuilder, FactoryPart, PhysicalResourceEstimation,
1316
PhysicalResourceEstimationResult,
1417
};
1518
mod layout;

resource_estimator/src/estimates/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ pub enum Error {
3737
#[error("No solution found for the provided maximum number of physical qubits.")]
3838
#[diagnostic(code("Qsc.Estimates.MaxPhysicalQubitsTooSmall"))]
3939
MaxPhysicalQubitsTooSmall,
40+
/// Constraint-based search only supports one magic state type.
41+
///
42+
/// ✅ This error cannot be triggered by the system, since only one magic
43+
/// state type is supported.
44+
#[error("Constraint-based search only supports one magic state type.")]
45+
#[diagnostic(code("Qsc.Estimates.MultipleMagicStatesNotSupported"))]
46+
MultipleMagicStatesNotSupported,
4047
/// The number of physical qubits required for a code cannot be computed.
4148
///
4249
/// ✅ This does not contain user data and can be logged

resource_estimator/src/estimates/factory.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ use probability::{distribution::Inverse, prelude::Binomial};
44

55
use super::Factory;
66

7+
/// Helper structs when dispatching multiple magic states to different factories
8+
mod dispatch;
9+
pub use dispatch::{BuilderDispatch2, FactoryDispatch2};
10+
11+
/// Helper structs for when no factories are used
12+
mod empty;
13+
pub use empty::NoFactories;
14+
715
pub trait DistillationUnit<P> {
816
fn num_output_states(&self) -> u64;
917
fn num_input_states(&self) -> u64;
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use crate::estimates::{ErrorCorrection, Factory, FactoryBuilder};
2+
use std::borrow::Cow;
3+
4+
/// Implements `Factory` to combine two factories for dispatching
5+
///
6+
/// It requires that all factories define the same code parameter type.
7+
#[derive(Clone)]
8+
pub enum FactoryDispatch2<Factory1, Factory2> {
9+
Factory1(Factory1),
10+
Factory2(Factory2),
11+
}
12+
13+
impl<Factory1: Factory, Factory2: Factory<Parameter = Factory1::Parameter>> Factory
14+
for FactoryDispatch2<Factory1, Factory2>
15+
{
16+
type Parameter = Factory1::Parameter;
17+
18+
fn physical_qubits(&self) -> u64 {
19+
match self {
20+
Self::Factory1(f) => f.physical_qubits(),
21+
Self::Factory2(f) => f.physical_qubits(),
22+
}
23+
}
24+
25+
fn duration(&self) -> u64 {
26+
match self {
27+
Self::Factory1(f) => f.duration(),
28+
Self::Factory2(f) => f.duration(),
29+
}
30+
}
31+
32+
fn num_output_states(&self) -> u64 {
33+
match self {
34+
Self::Factory1(f) => f.num_output_states(),
35+
Self::Factory2(f) => f.num_output_states(),
36+
}
37+
}
38+
39+
fn max_code_parameter(&self) -> Option<Cow<Self::Parameter>> {
40+
match self {
41+
Self::Factory1(f) => f.max_code_parameter(),
42+
Self::Factory2(f) => f.max_code_parameter(),
43+
}
44+
}
45+
}
46+
47+
/// Implements `FactoryBuilder` to combine two factory builders for dispatching
48+
///
49+
/// It will use `FactoryDispatch2` as factory type for the builder.
50+
pub struct BuilderDispatch2<Builder1, Builder2> {
51+
builder1: Builder1,
52+
builder2: Builder2,
53+
}
54+
55+
impl<Builder1: Default, Builder2: Default> Default for BuilderDispatch2<Builder1, Builder2> {
56+
fn default() -> Self {
57+
Self {
58+
builder1: Builder1::default(),
59+
builder2: Builder2::default(),
60+
}
61+
}
62+
}
63+
64+
impl<E: ErrorCorrection, Builder1: FactoryBuilder<E>, Builder2: FactoryBuilder<E>> FactoryBuilder<E>
65+
for BuilderDispatch2<Builder1, Builder2>
66+
{
67+
type Factory = FactoryDispatch2<Builder1::Factory, Builder2::Factory>;
68+
69+
fn find_factories(
70+
&self,
71+
ftp: &E,
72+
qubit: &std::rc::Rc<E::Qubit>,
73+
magic_state_type: usize,
74+
output_error_rate: f64,
75+
max_code_parameter: &E::Parameter,
76+
) -> Vec<Cow<Self::Factory>> {
77+
match magic_state_type {
78+
0 => self
79+
.builder1
80+
.find_factories(
81+
ftp,
82+
qubit,
83+
magic_state_type,
84+
output_error_rate,
85+
max_code_parameter,
86+
)
87+
.into_iter()
88+
.map(|f| Cow::Owned(FactoryDispatch2::Factory1(f.into_owned())))
89+
.collect(),
90+
1 => self
91+
.builder2
92+
.find_factories(
93+
ftp,
94+
qubit,
95+
magic_state_type,
96+
output_error_rate,
97+
max_code_parameter,
98+
)
99+
.into_iter()
100+
.map(|f| Cow::Owned(FactoryDispatch2::Factory2(f.into_owned())))
101+
.collect(),
102+
_ => unreachable!("factory builder only has two magic state types"),
103+
}
104+
}
105+
106+
/// Since this builder dispatch is for two factory builders, it can support
107+
/// two different magic state types.
108+
fn num_magic_state_types(&self) -> usize {
109+
2
110+
}
111+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use std::marker::PhantomData;
2+
3+
use crate::estimates::{ErrorCorrection, Factory, FactoryBuilder};
4+
5+
pub struct NoFactories<E> {
6+
phantom: PhantomData<E>,
7+
}
8+
9+
impl<E> Default for NoFactories<E> {
10+
fn default() -> Self {
11+
Self {
12+
phantom: PhantomData,
13+
}
14+
}
15+
}
16+
17+
#[derive(Clone)]
18+
pub struct NoFactory<P> {
19+
phantom: PhantomData<P>,
20+
}
21+
22+
impl<E: ErrorCorrection<Parameter = impl Clone>> FactoryBuilder<E> for NoFactories<E> {
23+
type Factory = NoFactory<E::Parameter>;
24+
25+
fn find_factories(
26+
&self,
27+
_ftp: &E,
28+
_qubit: &std::rc::Rc<<E as ErrorCorrection>::Qubit>,
29+
_magic_state_type: usize,
30+
_output_error_rate: f64,
31+
_max_code_parameter: &<E as ErrorCorrection>::Parameter,
32+
) -> Vec<std::borrow::Cow<Self::Factory>> {
33+
unreachable!()
34+
}
35+
36+
fn num_magic_state_types(&self) -> usize {
37+
0
38+
}
39+
}
40+
41+
impl<P: Clone> Factory for NoFactory<P> {
42+
type Parameter = P;
43+
44+
fn physical_qubits(&self) -> u64 {
45+
unreachable!()
46+
}
47+
48+
fn duration(&self) -> u64 {
49+
unreachable!()
50+
}
51+
52+
fn num_output_states(&self) -> u64 {
53+
unreachable!()
54+
}
55+
56+
fn max_code_parameter(&self) -> Option<std::borrow::Cow<Self::Parameter>> {
57+
unreachable!()
58+
}
59+
}
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
use super::ErrorBudget;
5+
6+
/// Trait to model post-layout logical overhead
47
pub trait Overhead {
8+
/// The number of logical qubits to execute the algorithm after mapping
9+
///
10+
/// This number does not include qubit used to produce magic states.
511
fn logical_qubits(&self) -> u64;
6-
fn logical_qubits_without_padding(&self) -> u64 {
7-
self.logical_qubits()
8-
}
9-
fn logical_depth(&self, num_magic_states_per_rotation: u64) -> u64;
10-
fn num_magic_states(&self, num_magic_states_per_rotation: u64) -> u64;
11-
fn num_magic_states_per_rotation(&self, eps_synthesis: f64) -> Option<u64>;
12+
13+
/// The number of logical unit cycles to execute the algorithm
14+
///
15+
/// This number is a lower bound for the execution time of the algorithm,
16+
/// and might be extended by assuming no-ops.
17+
fn logical_depth(&self, budget: &ErrorBudget) -> u64;
18+
19+
/// The number of magic states
20+
///
21+
/// The index is used to indicate the type of magic states and must be
22+
/// supported by available factory builders in the physical estimation.
23+
fn num_magic_states(&self, budget: &ErrorBudget, index: usize) -> u64;
1224
}

0 commit comments

Comments
 (0)