Skip to content

Commit

Permalink
Generic code with code distance and threshold (#1896)
Browse files Browse the repository at this point in the history
Provides a generic version for an error correction code that has a code
distance, threshold, and exponential error suppression. The system
version (with surface code and Floquet code as defaults, and
customizable via formula strings) is now implemented based on the
generic version. The generic version can also be used in other projects
via extensibility API.
  • Loading branch information
msoeken authored Sep 6, 2024
1 parent 26654c9 commit 72c32aa
Show file tree
Hide file tree
Showing 10 changed files with 523 additions and 447 deletions.
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

0 comments on commit 72c32aa

Please sign in to comment.