microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
source/resource_estimator/src/system/data/logical_counts.rs
151lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use crate::{ |
| 5 | estimates::{ErrorBudget, ErrorBudgetStrategy, Overhead}, |
| 6 | system::constants::{ |
| 7 | NUM_MEASUREMENTS_PER_R, NUM_MEASUREMENTS_PER_TOF, NUM_TS_PER_ROTATION_A_COEFFICIENT, |
| 8 | NUM_TS_PER_ROTATION_B_COEFFICIENT, |
| 9 | }, |
| 10 | }; |
| 11 | use serde::{Deserialize, Serialize}; |
| 12 | |
| 13 | use super::PartitioningOverhead; |
| 14 | |
| 15 | pub trait LayoutReportData { |
| 16 | fn num_qubits(&self) -> u64; |
| 17 | fn t_count(&self) -> u64; |
| 18 | fn rotation_count(&self) -> u64; |
| 19 | fn rotation_depth(&self) -> u64; |
| 20 | fn ccz_count(&self) -> u64; |
| 21 | fn ccix_count(&self) -> u64; |
| 22 | fn measurement_count(&self) -> u64; |
| 23 | fn num_ts_per_rotation(&self, eps_synthesis: f64) -> Option<u64>; |
| 24 | } |
| 25 | |
| 26 | /// Resource counts output from `qir_estimate_counts` program |
| 27 | #[derive(Default, Debug, Deserialize, Serialize)] |
| 28 | #[serde( |
| 29 | rename_all(deserialize = "camelCase", serialize = "camelCase"), |
| 30 | deny_unknown_fields |
| 31 | )] |
| 32 | pub struct LogicalResourceCounts { |
| 33 | pub num_qubits: u64, |
| 34 | #[serde(default)] |
| 35 | pub t_count: u64, |
| 36 | #[serde(default)] |
| 37 | pub rotation_count: u64, |
| 38 | #[serde(default)] |
| 39 | pub rotation_depth: u64, |
| 40 | #[serde(default)] |
| 41 | pub ccz_count: u64, |
| 42 | #[serde(default)] |
| 43 | pub ccix_count: u64, |
| 44 | #[serde(default)] |
| 45 | pub measurement_count: u64, |
| 46 | } |
| 47 | |
| 48 | /// Models the logical resources after layout |
| 49 | /// |
| 50 | /// The logical resources comprise the logical depth, the number of qubits, and |
| 51 | /// the number of T states. If there are rotations, optionally the number of T |
| 52 | /// gates per rotation are specified. |
| 53 | impl Overhead for LogicalResourceCounts { |
| 54 | // number of qubits per one logical qubit (part of Q in paper) |
| 55 | fn logical_qubits(&self) -> Result<u64, String> { |
| 56 | // number of logical qubits for padding (part of Q in paper) |
| 57 | let qubit_padding = ((8 * self.num_qubits) as f64).sqrt().ceil() as u64 + 1; |
| 58 | |
| 59 | Ok(2 * self.num_qubits + qubit_padding) |
| 60 | } |
| 61 | |
| 62 | fn logical_depth(&self, budget: &ErrorBudget) -> Result<u64, String> { |
| 63 | Ok( |
| 64 | (self.measurement_count + self.rotation_count + self.t_count) * NUM_MEASUREMENTS_PER_R |
| 65 | + (self.ccz_count + self.ccix_count) * NUM_MEASUREMENTS_PER_TOF |
| 66 | + self |
| 67 | .num_ts_per_rotation(budget.rotations()) |
| 68 | .unwrap_or_default() |
| 69 | * self.rotation_depth |
| 70 | * NUM_MEASUREMENTS_PER_R, |
| 71 | ) |
| 72 | } |
| 73 | |
| 74 | fn num_magic_states(&self, budget: &ErrorBudget, _index: usize) -> Result<u64, String> { |
| 75 | Ok(4 * (self.ccz_count + self.ccix_count) |
| 76 | + self.t_count |
| 77 | + self |
| 78 | .num_ts_per_rotation(budget.rotations()) |
| 79 | .unwrap_or_default() |
| 80 | * self.rotation_count) |
| 81 | } |
| 82 | |
| 83 | fn prune_error_budget(&self, budget: &mut ErrorBudget, strategy: ErrorBudgetStrategy) { |
| 84 | if matches![strategy, ErrorBudgetStrategy::PruneLogicalAndRotations] { |
| 85 | if let Some(num_ts_per_rotation) = self.num_ts_per_rotation(budget.rotations()) { |
| 86 | let new_rotations_budget = (self.rotation_count as f64) |
| 87 | / 2.0_f64.powf( |
| 88 | ((num_ts_per_rotation as f64) - NUM_TS_PER_ROTATION_B_COEFFICIENT) |
| 89 | / NUM_TS_PER_ROTATION_A_COEFFICIENT, |
| 90 | ); |
| 91 | |
| 92 | let diff = budget.rotations() - new_rotations_budget; |
| 93 | budget.set_rotations(new_rotations_budget); |
| 94 | budget.set_magic_states(budget.magic_states() + diff); |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | impl PartitioningOverhead for LogicalResourceCounts { |
| 101 | fn has_tgates(&self) -> bool { |
| 102 | self.t_count > 0 || self.ccz_count > 0 || self.ccix_count > 0 || self.rotation_count > 0 |
| 103 | } |
| 104 | |
| 105 | fn has_rotations(&self) -> bool { |
| 106 | self.rotation_count > 0 |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | impl LayoutReportData for LogicalResourceCounts { |
| 111 | fn num_qubits(&self) -> u64 { |
| 112 | self.num_qubits |
| 113 | } |
| 114 | |
| 115 | fn t_count(&self) -> u64 { |
| 116 | self.t_count |
| 117 | } |
| 118 | |
| 119 | fn rotation_count(&self) -> u64 { |
| 120 | self.rotation_count |
| 121 | } |
| 122 | |
| 123 | fn rotation_depth(&self) -> u64 { |
| 124 | self.rotation_depth |
| 125 | } |
| 126 | |
| 127 | fn ccz_count(&self) -> u64 { |
| 128 | self.ccz_count |
| 129 | } |
| 130 | |
| 131 | fn ccix_count(&self) -> u64 { |
| 132 | self.ccix_count |
| 133 | } |
| 134 | |
| 135 | fn measurement_count(&self) -> u64 { |
| 136 | self.measurement_count |
| 137 | } |
| 138 | |
| 139 | fn num_ts_per_rotation(&self, eps_synthesis: f64) -> Option<u64> { |
| 140 | if self.rotation_count > 0 { |
| 141 | Some( |
| 142 | (NUM_TS_PER_ROTATION_A_COEFFICIENT |
| 143 | * ((self.rotation_count as f64) / eps_synthesis).log2() |
| 144 | + NUM_TS_PER_ROTATION_B_COEFFICIENT) |
| 145 | .ceil() as _, |
| 146 | ) |
| 147 | } else { |
| 148 | None |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |