Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic code with code distance and threshold #1896

Merged
merged 2 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions resource_estimator/src/estimates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod error;
pub use error::Error;
mod error_budget;
pub use error_budget::ErrorBudget;
mod error_correction;
pub use error_correction::{CodeWithThresholdAndDistance, CodeWithThresholdAndDistanceEvaluator};
mod factory;
pub use factory::{
BuilderDispatch2, DistillationRound, DistillationUnit, FactoryBuildError, FactoryDispatch2,
Expand Down
151 changes: 151 additions & 0 deletions resource_estimator/src/estimates/error_correction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use super::ErrorCorrection;

pub trait CodeWithThresholdAndDistanceEvaluator {
type Qubit;

fn physical_error_rate(&self, qubit: &Self::Qubit) -> f64;
fn physical_qubits(&self, code_distance: u64) -> Result<u64, String>;
fn logical_cycle_time(&self, qubit: &Self::Qubit, code_distance: u64) -> Result<u64, String>;
}

pub struct CodeWithThresholdAndDistance<Evaluator> {
evaluator: Evaluator,
crossing_prefactor: f64,
error_correction_threshold: f64,
max_code_distance: Option<u64>,
}

impl<Evaluator> CodeWithThresholdAndDistance<Evaluator> {
pub fn new(
evaluator: Evaluator,
crossing_prefactor: f64,
error_correction_threshold: f64,
) -> Self {
Self {
evaluator,
crossing_prefactor,
error_correction_threshold,
max_code_distance: None,
}
}

pub fn with_max_code_distance(
evaluator: Evaluator,
crossing_prefactor: f64,
error_correction_threshold: f64,
max_code_distance: u64,
) -> Self {
Self {
evaluator,
crossing_prefactor,
error_correction_threshold,
max_code_distance: Some(max_code_distance),
}
}

pub fn crossing_prefactor(&self) -> f64 {
self.crossing_prefactor
}

pub fn set_crossing_prefactor(&mut self, crossing_prefactor: f64) {
self.crossing_prefactor = crossing_prefactor;
}

pub fn error_correction_threshold(&self) -> f64 {
self.error_correction_threshold
}

pub fn set_error_correction_threshold(&mut self, error_correction_threshold: f64) {
self.error_correction_threshold = error_correction_threshold;
}

pub fn max_code_distance(&self) -> Option<&u64> {
self.max_code_distance.as_ref()
}

pub fn set_max_code_distance(&mut self, max_code_distance: u64) {
self.max_code_distance = Some(max_code_distance);
}

pub fn evaluator(&self) -> &Evaluator {
&self.evaluator
}

pub fn evaluator_mut(&mut self) -> &mut Evaluator {
&mut self.evaluator
}
}

impl<Evaluator: CodeWithThresholdAndDistanceEvaluator> ErrorCorrection
for CodeWithThresholdAndDistance<Evaluator>
{
type Qubit = Evaluator::Qubit;
type Parameter = u64;

fn physical_qubits(&self, code_distance: &u64) -> Result<u64, String> {
self.evaluator.physical_qubits(*code_distance)
}

fn logical_qubits(&self, _code_distance: &u64) -> Result<u64, String> {
Ok(1)
}

fn logical_cycle_time(&self, qubit: &Self::Qubit, code_distance: &u64) -> Result<u64, String> {
self.evaluator.logical_cycle_time(qubit, *code_distance)
}

fn logical_error_rate(&self, qubit: &Self::Qubit, code_distance: &u64) -> Result<f64, String> {
let physical_error_rate = self.evaluator.physical_error_rate(qubit);

if physical_error_rate > self.error_correction_threshold {
Err(format!(
"invalid value for 'physical_error_rate', expected value between 0 and {}",
self.error_correction_threshold
))
} else {
Ok(self.crossing_prefactor
* ((physical_error_rate / self.error_correction_threshold)
.powi((*code_distance as i32 + 1) / 2)))
}
}

// Compute code distance d (Equation (E2) in paper)
fn compute_code_parameter(
&self,
qubit: &Self::Qubit,
required_logical_qubit_error_rate: f64,
) -> Result<u64, String> {
let physical_error_rate = self.evaluator.physical_error_rate(qubit);
let numerator = 2.0 * (self.crossing_prefactor / required_logical_qubit_error_rate).ln();
let denominator = (self.error_correction_threshold / physical_error_rate).ln();

let code_distance = (((numerator / denominator) - 1.0).ceil() as u64) | 0x1;

if let Some(max_distance) = self.max_code_distance {
if max_distance < code_distance {
return Err(format!("The computed code distance {code_distance} is too high; maximum allowed code distance is {max_distance}; try increasing the total logical error budget"));
}
}

Ok(code_distance)
}

fn code_parameter_range(
&self,
lower_bound: Option<&Self::Parameter>,
) -> impl Iterator<Item = Self::Parameter> {
(lower_bound.copied().unwrap_or(1)..=self.max_code_distance.unwrap_or(u64::MAX)).step_by(2)
}

fn code_parameter_cmp(
&self,
_qubit: &Self::Qubit,
p1: &Self::Parameter,
p2: &Self::Parameter,
) -> std::cmp::Ordering {
p1.cmp(p2)
}
}
3 changes: 2 additions & 1 deletion resource_estimator/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub use self::optimization::TFactoryBuilder;
pub use self::{data::LogicalResourceCounts, error::Error};
use data::{EstimateType, JobParams};
pub use data::{LayoutReportData, PartitioningOverhead};
use modeling::load_protocol_from_specification;
use serde::Serialize;

pub(crate) type Result<T> = std::result::Result<T, error::Error>;
Expand Down Expand Up @@ -77,7 +78,7 @@ fn estimate_single<L: Overhead + LayoutReportData + PartitioningOverhead + Seria
) -> Result<data::Success<L>> {
let qubit = job_params.qubit_params().clone();

let ftp = Protocol::load_from_specification(job_params.qec_scheme_mut(), &qubit)?;
let ftp = load_protocol_from_specification(job_params.qec_scheme_mut(), &qubit)?;
let distillation_unit_templates = job_params
.distillation_unit_specifications()
.as_templates()?;
Expand Down
Loading
Loading