From fb6f3e487ac008e1f3c059fa6ea0d77d1fb77864 Mon Sep 17 00:00:00 2001 From: Matthew Harrigan Date: Thu, 18 Jul 2024 18:11:25 +0000 Subject: [PATCH] [surface code] DataBlock refactor (#1141) * DataBlock refactor * fix notebook * Spell everything * Fix notebook --- qualtran/surface_code/__init__.py | 1 + qualtran/surface_code/azure_cost_model.ipynb | 15 +- qualtran/surface_code/azure_cost_model.py | 2 +- .../surface_code/azure_cost_model_test.py | 5 + qualtran/surface_code/ccz2t_cost_model.py | 19 +- qualtran/surface_code/data_block.py | 240 +++++++++++------- qualtran/surface_code/data_block_test.py | 7 +- qualtran/surface_code/magic_count.py | 6 +- ...quantum_error_correction_scheme_summary.py | 19 +- ...um_error_correction_scheme_summary_test.py | 7 + qualtran/surface_code/thc_compilation.ipynb | 22 +- qualtran/surface_code/ui.py | 4 +- 12 files changed, 219 insertions(+), 128 deletions(-) diff --git a/qualtran/surface_code/__init__.py b/qualtran/surface_code/__init__.py index c49eab63a..776e357dd 100644 --- a/qualtran/surface_code/__init__.py +++ b/qualtran/surface_code/__init__.py @@ -35,6 +35,7 @@ BeverlandSuperconductingQubits, BeverlandTrappedIonQubits, FowlerSuperconductingQubits, + LogicalErrorModel, QuantumErrorCorrectionSchemeSummary, ) from qualtran.surface_code.reference import Reference diff --git a/qualtran/surface_code/azure_cost_model.ipynb b/qualtran/surface_code/azure_cost_model.ipynb index 9b231b4b5..20a4f1944 100644 --- a/qualtran/surface_code/azure_cost_model.ipynb +++ b/qualtran/surface_code/azure_cost_model.ipynb @@ -226,7 +226,7 @@ "source": [ "from qualtran.surface_code.data_block import FastDataBlock\n", "\n", - "logical_qubits = FastDataBlock.grid_size(n_algo_qubits=quantum_dynamics_specs.algorithm_qubits)\n", + "logical_qubits = FastDataBlock.get_n_tiles(n_algo_qubits=quantum_dynamics_specs.algorithm_qubits)\n", "\n", "print('Q =', logical_qubits)" ] @@ -398,7 +398,7 @@ "metadata": {}, "outputs": [], "source": [ - "logical_qubits = FastDataBlock.grid_size(n_algo_qubits=quantum_chemistry_specs.algorithm_qubits)\n", + "logical_qubits = FastDataBlock.get_n_tiles(n_algo_qubits=quantum_chemistry_specs.algorithm_qubits)\n", "\n", "print('Q =', logical_qubits)" ] @@ -572,7 +572,7 @@ "metadata": {}, "outputs": [], "source": [ - "logical_qubits = FastDataBlock.grid_size(n_algo_qubits=shor_specs.algorithm_qubits)\n", + "logical_qubits = FastDataBlock.get_n_tiles(n_algo_qubits=shor_specs.algorithm_qubits)\n", "\n", "print('Q =', logical_qubits)" ] @@ -699,7 +699,7 @@ ], "metadata": { "kernelspec": { - "display_name": "qualtran", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -713,10 +713,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" - }, - "orig_nbformat": 4 + "version": "3.11.8" + } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/qualtran/surface_code/azure_cost_model.py b/qualtran/surface_code/azure_cost_model.py index b681eabea..19610df68 100644 --- a/qualtran/surface_code/azure_cost_model.py +++ b/qualtran/surface_code/azure_cost_model.py @@ -78,7 +78,7 @@ def code_distance( qec: Quantum Error Correction Scheme. physical_error_rate: The physical error rate of the device. """ - q = FastDataBlock.grid_size(n_algo_qubits=int(alg.algorithm_qubits)) + q = FastDataBlock.get_n_tiles(n_algo_qubits=int(alg.algorithm_qubits)) return qec.code_distance_from_budget(physical_error_rate, error_budget / (3 * q * time_steps)) diff --git a/qualtran/surface_code/azure_cost_model_test.py b/qualtran/surface_code/azure_cost_model_test.py index 61635e177..952cf9fd5 100644 --- a/qualtran/surface_code/azure_cost_model_test.py +++ b/qualtran/surface_code/azure_cost_model_test.py @@ -15,6 +15,7 @@ import pytest from attrs import frozen +import qualtran.testing as qlt_testing from qualtran.surface_code import azure_cost_model from qualtran.surface_code.algorithm_summary import AlgorithmSummary from qualtran.surface_code.quantum_error_correction_scheme_summary import ( @@ -109,3 +110,7 @@ def test_t_states(test: Test): test.error_budget, test.alg, rotation_model=BeverlandEtAlRotationCost ) assert got == pytest.approx(test.t_states, rel=0.1) + + +def test_notebook(): + qlt_testing.execute_notebook('azure_cost_model') diff --git a/qualtran/surface_code/ccz2t_cost_model.py b/qualtran/surface_code/ccz2t_cost_model.py index b99c69e48..b7530d068 100644 --- a/qualtran/surface_code/ccz2t_cost_model.py +++ b/qualtran/surface_code/ccz2t_cost_model.py @@ -182,17 +182,20 @@ def get_ccz2t_costs( factory: magic state factory configuration. Used to evaluate distillation error and cost. data_block: data block configuration. Used to evaluate data error and footprint. """ + err_model = qec.LogicalErrorModel( + qec_scheme=qec.FowlerSuperconductingQubits, physical_error=phys_err + ) distillation_error = factory.distillation_error(n_magic=n_magic, phys_err=phys_err) n_generation_cycles = factory.n_cycles(n_magic=n_magic, phys_err=phys_err) - n_consumption_cycles = ( - n_magic.n_t / 4 + n_magic.n_ccz - ) * data_block.n_cycles_to_consume_a_magic_state() + n_consumption_cycles = data_block.n_cycles( + n_logical_gates=n_magic, logical_error_model=err_model + ) n_cycles = max(n_generation_cycles, n_consumption_cycles) data_error = data_block.data_error( - n_algo_qubits=n_algo_qubits, n_cycles=int(n_cycles), phys_err=phys_err + n_algo_qubits=n_algo_qubits, n_cycles=int(n_cycles), logical_error_model=err_model ) failure_prob = distillation_error + data_error - footprint = factory.footprint() + data_block.footprint(n_algo_qubits=n_algo_qubits) + footprint = factory.footprint() + data_block.n_physical_qubits(n_algo_qubits=n_algo_qubits) duration_hr = (cycle_time_us * n_cycles) / (1_000_000 * 60 * 60) return PhysicalCost(failure_prob=failure_prob, footprint=footprint, duration_hr=duration_hr) @@ -255,11 +258,7 @@ def get_ccz2t_costs_from_error_budget( data_d = qec.FowlerSuperconductingQubits.code_distance_from_budget( physical_error_rate=phys_err, budget=target_err_per_round ) - data_block = SimpleDataBlock( - data_d=data_d, - routing_overhead=routing_overhead, - qec_scheme=qec.FowlerSuperconductingQubits, - ) + data_block = SimpleDataBlock(data_d=data_d, routing_overhead=routing_overhead) return get_ccz2t_costs( n_magic=n_magic, diff --git a/qualtran/surface_code/data_block.py b/qualtran/surface_code/data_block.py index f5c45d405..1416e83fd 100644 --- a/qualtran/surface_code/data_block.py +++ b/qualtran/surface_code/data_block.py @@ -14,113 +14,172 @@ import abc import math -from typing import Optional +from typing import TYPE_CHECKING -from attrs import field, frozen +from attrs import frozen -import qualtran.surface_code.quantum_error_correction_scheme_summary as qec -from qualtran.surface_code.reference import Reference +if TYPE_CHECKING: + from qualtran.resource_counting import GateCounts + from qualtran.surface_code import ( + LogicalErrorModel, + MagicCount, + QuantumErrorCorrectionSchemeSummary, + ) class DataBlock(metaclass=abc.ABCMeta): - """A cost model for the data block of a surface code compilation. + """Methods for modeling the costs of the data block of a surface code compilation. + + The number of algorithm qubits is reported by Qualtran as a logical cost of a bloq. The + surface code is a rate-1 code, so each bit of data needs at least one surface code tile. Due + to locality constraints imposed by the 2D surface code combined with the need to interact + qubits that aren’t necessarily local, additional tiles are needed to actually execute a program. + + Each data block is responsible for reporting the number of tiles required to store a certain + number of algorithm qubits; as well as the number of time steps required to consume a magic + state. Different data blocks exist in the literature, and data block provides a different + space-time tradeoff. - A surface code layout is segregated into qubits dedicated to magic state distillation - and others dedicated to storing the actual data being processed. The latter area is - called the data block, and we provide its costs here. + The space occupied by the data block is to be contrasted with the space used for magic + state distillation. """ + @property @abc.abstractmethod - def footprint(self, n_algo_qubits: int) -> int: - """The number of physical qubits used by the data block. + def data_d(self): + """The code distance used to store the data in the data block.""" + + @abc.abstractmethod + def n_tiles(self, n_algo_qubits: int) -> int: + """The number of surface code tiles used to store a given number of algorithm qubits. + + We define an “algorithm qubit” to be a qubit used in the routing of algorithm-relevant + quantum data in a bloq. A physical qubit is a physical system that can encode one qubit, + albeit noisily. Specific to the surface code, we define a “tile” to be the minimal area + of physical qubits necessary to encode one logical qubit to a particular code distance. + A tile can store an algorithm qubit, can be used for ancillary purposes like routing, + or can be left idle. A tile is usually a square grid of $2d^2$ physical qubits. - Attributes: - n_algo_qubits: The number of algorithm qubits whose data must be stored and - accessed. + DataBlock implementations must override this method. This method is used by + `self.n_phys_qubits` to report the total number of physical qubits. + + Args: + n_algo_qubits: The number of algorithm qubits to compute the number of tiles for. + + Returns: + The number of tiles used by this data block to store the given number of algorithm + qubits. """ + @property @abc.abstractmethod - def data_error(self, n_algo_qubits: int, n_cycles: int, phys_err: float) -> float: - """The error associated with storing data on `n_algo_qubits` for `n_cycles`.""" + def n_steps_to_consume_a_magic_state(self): + """The number of surface code steps to consume a magic state. - @abc.abstractmethod - def n_cycles_to_consume_a_magic_state(self) -> int: - """The worst case number of cycles needed to consume a magic state.""" + We must teleport in "magic states" to do non-Clifford operations on our algorithmic + data qubits. The layout of the data block can limit the number magic states consumed + per unit time. + + One surface code step is `data_d` cycles of error correction. + + DataBlock imlpementation must override this method. This method is used by + `self.n_cycles` to report the total number of cycles required. + """ + + def n_cycles( + self, n_logical_gates: 'MagicCount', logical_error_model: 'LogicalErrorModel' + ) -> int: + """The number of surface code cycles to apply the number of gates to the data block. + + Note that only the Litinski (2019) derived data blocks model a limit on the number of + magic states consumed per step. Other data blocks return "zero" for the number of cycles + due to the data block. When using those data block designs, it is assumed that the + number of cycles taken by the magic state factories is the limiting factor in the + computation. + """ + counts = n_logical_gates.total_t_and_ccz_count() + n_steps = (counts['n_t'] + counts['n_ccz']) * self.n_steps_to_consume_a_magic_state + n_cycles = self.data_d * n_steps + return n_cycles + + def n_physical_qubits(self, n_algo_qubits: int) -> int: + """The number of physical qubits used by the data block.""" + n_phys_per_tile = 2 * self.data_d**2 + return n_phys_per_tile * self.n_tiles(n_algo_qubits) + + def data_error( + self, n_algo_qubits: int, n_cycles: int, logical_error_model: 'LogicalErrorModel' + ) -> float: + """The error associated with storing data on `n_algo_qubits` for `n_cycles`.""" + # spacetime_volue = number of data cells x number of cycles they will live for. + spacetime_volume = self.n_tiles(n_algo_qubits) * n_cycles + return spacetime_volume * logical_error_model(self.data_d) @frozen class SimpleDataBlock(DataBlock): """A simple data block that uses a fixed code distance and routing overhead. + The simple data block approximates the total tile usage by considering one tile + per algorithm qubit plus a constant factor overhead presumed to be used for routing. + + Note: the spreadsheet from the reference had a 50% overhead hardcoded for + some of the cells using this quantity and variable (but set to 50% as default) + for others. + Attributes: data_d: The code distance `d` for protecting the qubits in the data block. routing_overhead: As an approximation, assume some routing or auxiliary qubits proportional to the number of algorithm qubits. - qec_scheme: Underlying quantum error correction scheme. - reference: A description of the source of the model. + + References: + Efficient magic state factories with a catalyzed |CCZ> to 2|T> transformation. + https://arxiv.org/abs/1812.01238 """ data_d: int routing_overhead: float = 0.5 - qec_scheme: qec.QuantumErrorCorrectionSchemeSummary = qec.FowlerSuperconductingQubits - reference: Optional[Reference] = None - - def n_logical_qubits(self, n_algo_qubits: int) -> int: - """Number of logical qubits including overhead. - Note: the spreadsheet from the reference had a 50% overhead hardcoded for - some of the cells using this quantity and variable (but set to 50% as default) - for others. - """ + def n_tiles(self, n_algo_qubits: int) -> int: return math.ceil((1 + self.routing_overhead) * n_algo_qubits) - def footprint(self, n_algo_qubits: int) -> int: - """The number of physical qubits used by the data block.""" - n_phys_per_logical = self.qec_scheme.physical_qubits(self.data_d) - return self.n_logical_qubits(n_algo_qubits) * n_phys_per_logical - - def data_error(self, n_algo_qubits: int, n_cycles: int, phys_err: float) -> float: - """The error associated with storing data on `n_algo_qubits` for `n_cycles`.""" - # spacetime_volue = number of data cells x number of cycles they will live for. - spacetime_volume = self.n_logical_qubits(n_algo_qubits) * n_cycles - return spacetime_volume * self.qec_scheme.logical_error_rate( - physical_error_rate=phys_err, code_distance=self.data_d - ) - - def n_cycles_to_consume_a_magic_state(self) -> int: - return self.data_d + @property + def n_steps_to_consume_a_magic_state(self) -> int: + # The simple data block assume that an unbounded number of magic states can be + # processed simultaneously and that the computation is bounded by the time to + # produce the magic states. + return 0 @frozen -class CompactDataBlock(SimpleDataBlock): - r"""The compact data block uses a fixed code distance and routing overhead. +class CompactDataBlock(DataBlock): + r"""The compact data block uses a fixed code distance and one, long access hallway. The compact data block lays $n$ qubit batches in grid of shape (3, $n/2$) where the data batches are lined in the first and last row with the middle row being - an ancilla region. This lowers the memory footprint of the block at the cost of an + an ancilla region. This lowers the space footprint of the block at the cost of an increased number of cycles to consume a magic state. Attributes: data_d: The code distance `d` for protecting the qubits in the data block. - qec_scheme: Underlying quantum error correction scheme. - reference: A description of the source of the model. References: - [A Game of Surface Codes](https://arxiv.org/abs/1808.02892) - page 7, figure 9 + [A Game of Surface Codes](https://arxiv.org/abs/1808.02892). + Litinski (2019). Page 7, figure 9 """ - routing_overhead: float = field(default=0.5, init=False) - reference: Reference = field( - default=Reference(url='https://arxiv.org/abs/1808.02892', page=7), init=False - ) + data_d: int - def n_cycles_to_consume_a_magic_state(self) -> int: - return 9 * self.data_d + def n_tiles(self, n_algo_qubits: int) -> int: + return math.ceil(1.5 * n_algo_qubits) + + @property + def n_steps_to_consume_a_magic_state(self) -> int: + return 9 @frozen -class IntermediateDataBlock(SimpleDataBlock): +class IntermediateDataBlock(DataBlock): r"""The intermediate data block uses a fixed code distance and routing overhead. The intermediate data block lays $n$ qubit batches in grid of shape (2, $2n+2$) where @@ -129,20 +188,20 @@ class IntermediateDataBlock(SimpleDataBlock): Attributes: data_d: The code distance `d` for protecting the qubits in the data block. qec_scheme: Underlying quantum error correction scheme. - reference: A description of the source of the model. References: - [A Game of Surface Codes](https://arxiv.org/abs/1808.02892) - page 9, figure 13a + [A Game of Surface Codes](https://arxiv.org/abs/1808.02892). + Litinski (2019). Page 9, figure 13a """ - routing_overhead: float = field(default=1.0, init=False) - reference: Reference = field( - default=Reference(url='https://arxiv.org/abs/1808.02892', page=8), init=False - ) + data_d: int - def n_cycles_to_consume_a_magic_state(self) -> int: - return 5 * self.data_d + def n_tiles(self, n_algo_qubits: int) -> int: + return math.ceil(2 * n_algo_qubits) + + @property + def n_steps_to_consume_a_magic_state(self) -> int: + return 5 @frozen @@ -152,52 +211,41 @@ class FastDataBlock(DataBlock): The fast data block lays $n$ qubit batches in a square grid of side length $1 + \sqrt{2n}$ where the bottom row is an ancilla region and the top $\sqrt{2n}x\sqrt{2n}$ region is divided into alternating data and ancilla columns. + The increased footprint is to be able to consume magic states in a single timestep. Attributes: data_d: The code distance `d` for protecting the qubits in the data block. qec_scheme: Underlying quantum error correction scheme. - reference: A description of the source of the model. References: - [A Game of Surface Codes](https://arxiv.org/abs/1808.02892) - page 9, figure 13b + [A Game of Surface Codes](https://arxiv.org/abs/1808.02892). + Litinski (2019). Page 9, figure 13b """ data_d: int - qec_scheme: qec.QuantumErrorCorrectionSchemeSummary = qec.FowlerSuperconductingQubits - reference: Reference = field( - default=Reference(url='https://arxiv.org/abs/1808.02892', page=9), init=False - ) @staticmethod - def grid_size(n_algo_qubits: int) -> int: + def get_n_tiles(n_algo_qubits: int): + # This static method can be used in contexts where we want to know the number + # of tiles independent of `self.data_d`. return math.ceil(2 * n_algo_qubits + math.sqrt(8 * n_algo_qubits) + 1) - def footprint(self, n_algo_qubits: int) -> int: - return FastDataBlock.grid_size(n_algo_qubits) + def n_tiles(self, n_algo_qubits: int) -> int: + return self.get_n_tiles(n_algo_qubits) - def data_error(self, n_algo_qubits: int, n_cycles: int, phys_err: float) -> float: - """The error associated with storing data on `n_algo_qubits` for `n_cycles`.""" - # spacetime_volue = number of data cells x number of cycles they will live for. - spacetime_volume = self.n_logical_qubits(n_algo_qubits) * n_cycles - return spacetime_volume * self.qec_scheme.logical_error_rate( - physical_error_rate=phys_err, code_distance=self.data_d - ) - - def n_logical_qubits(self, n_algo_qubits: int) -> int: - return FastDataBlock.grid_size(n_algo_qubits) + @property + def n_steps_to_consume_a_magic_state(self) -> int: + return 1 - def n_cycles_to_consume_a_magic_state(self) -> int: - return self.data_d - - @staticmethod + @classmethod def from_error_budget( + cls, error_budget: float, n_algo_qubits: int, - qec_scheme: qec.QuantumErrorCorrectionSchemeSummary, - physical_error_rate: float, + qec_scheme: 'QuantumErrorCorrectionSchemeSummary', + phys_err_rate: float, ) -> 'FastDataBlock': - q = FastDataBlock.grid_size(n_algo_qubits) - d = qec_scheme.code_distance_from_budget(physical_error_rate, error_budget / q) - return FastDataBlock(data_d=d, qec_scheme=qec_scheme) + q = FastDataBlock.get_n_tiles(n_algo_qubits) + d = qec_scheme.code_distance_from_budget(phys_err_rate, error_budget / q) + return cls(data_d=d) diff --git a/qualtran/surface_code/data_block_test.py b/qualtran/surface_code/data_block_test.py index 2c5e25bd2..ccfb18dc9 100644 --- a/qualtran/surface_code/data_block_test.py +++ b/qualtran/surface_code/data_block_test.py @@ -15,7 +15,7 @@ import pytest -from qualtran.surface_code import FastDataBlock +from qualtran.surface_code import FastDataBlock, FowlerSuperconductingQubits, LogicalErrorModel @pytest.mark.parametrize( @@ -23,7 +23,8 @@ [[100, 230, 0.69], [1318, 2740, 8.22], [12581, 25481, 76.443]], ) def test_fast_block(logical_qubits, logical_qubits_with_routing, data_error): - assert FastDataBlock.grid_size(n_algo_qubits=logical_qubits) == logical_qubits_with_routing + assert FastDataBlock.get_n_tiles(n_algo_qubits=logical_qubits) == logical_qubits_with_routing + err_model = LogicalErrorModel(qec_scheme=FowlerSuperconductingQubits, physical_error=1e-3) assert FastDataBlock(3).data_error( - n_algo_qubits=logical_qubits, n_cycles=3, phys_err=1e-3 + n_algo_qubits=logical_qubits, n_cycles=3, logical_error_model=err_model ) == pytest.approx(data_error) diff --git a/qualtran/surface_code/magic_count.py b/qualtran/surface_code/magic_count.py index 36f6edbdf..b5f23eae6 100644 --- a/qualtran/surface_code/magic_count.py +++ b/qualtran/surface_code/magic_count.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Union +from typing import Dict, Union from attrs import field, frozen, validators @@ -40,3 +40,7 @@ def __mul__(self, other: Union[float, int]) -> 'MagicCount': def __rmul__(self, other: Union[float, int]) -> 'MagicCount': return self.__mul__(other) + + def total_t_and_ccz_count(self) -> Dict[str, float]: + # TODO(mpharrigan): Temporary shim before removal of `MagicCount`. + return {'n_t': self.n_t, 'n_ccz': self.n_ccz} diff --git a/qualtran/surface_code/quantum_error_correction_scheme_summary.py b/qualtran/surface_code/quantum_error_correction_scheme_summary.py index ce28adbee..26e8f3aca 100644 --- a/qualtran/surface_code/quantum_error_correction_scheme_summary.py +++ b/qualtran/surface_code/quantum_error_correction_scheme_summary.py @@ -21,7 +21,7 @@ @frozen -class QuantumErrorCorrectionSchemeSummary(abc.ABC): +class QuantumErrorCorrectionSchemeSummary(metaclass=abc.ABCMeta): r"""QuantumErrorCorrectionSchemeSummary represents a high-level view of a QEC scheme. QuantumErrorCorrectionSchemeSummary provides estimates for the logical error rate, @@ -110,6 +110,23 @@ def error_detection_circuit_time_us(self, code_distance: int) -> float: return self.single_stabilizer_time_us * code_distance +@frozen +class LogicalErrorModel: + """A model for getting the logical error rate at a given code distance. + + This curries a physical error rate with the QEC scheme, so various physical + cost models can calculate the logical error rate given a particular code distance. + """ + + physical_error: float + _qec_scheme: 'QuantumErrorCorrectionSchemeSummary' + + def __call__(self, code_distance: int): + return self._qec_scheme.logical_error_rate( + code_distance=code_distance, physical_error_rate=self.physical_error + ) + + BeverlandSuperconductingQubits = SimpliedSurfaceCode( error_rate_scaler=0.03, error_rate_threshold=0.01, diff --git a/qualtran/surface_code/quantum_error_correction_scheme_summary_test.py b/qualtran/surface_code/quantum_error_correction_scheme_summary_test.py index 77e98bea8..922c75dee 100644 --- a/qualtran/surface_code/quantum_error_correction_scheme_summary_test.py +++ b/qualtran/surface_code/quantum_error_correction_scheme_summary_test.py @@ -54,3 +54,10 @@ def test_invert_error_at(): ) > budget ) + + +def test_logical_error_model(): + ler = qecs.LogicalErrorModel( + qec_scheme=qecs.BeverlandSuperconductingQubits, physical_error=1e-3 + ) + assert ler(code_distance=3) == pytest.approx(3e-4) diff --git a/qualtran/surface_code/thc_compilation.ipynb b/qualtran/surface_code/thc_compilation.ipynb index 22843dd8d..11d9075e6 100644 --- a/qualtran/surface_code/thc_compilation.ipynb +++ b/qualtran/surface_code/thc_compilation.ipynb @@ -54,6 +54,16 @@ "Alternatively, qualtran provides a function to perform grid search over factories and data blocks, optimizing the cost (in terms of spacetime volume, total time or any other given ordering)." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from qualtran.surface_code import LogicalErrorModel, FowlerSuperconductingQubits\n", + "err_model = LogicalErrorModel(qec_scheme=FowlerSuperconductingQubits, physical_error=1e-3)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -67,7 +77,7 @@ " n_magic=n_magic,\n", " n_algo_qubits=n_data_qubits,\n", " error_budget=1e-2,\n", - " phys_err=1e-3,\n", + " phys_err=err_model.physical_error,\n", " factory_iter=iter_ccz2t_factories(n_factories=4), # use 4 CCZ factories in parallel\n", " cost_function=(lambda pc: pc.duration_hr) # optimize over total time\n", ")" @@ -79,9 +89,9 @@ "metadata": {}, "outputs": [], "source": [ - "distillation_error = best_factory.distillation_error(n_magic, phys_err=1e-3)\n", + "distillation_error = best_factory.distillation_error(n_magic, phys_err=err_model.physical_error)\n", "data_error = best_data_block.data_error(\n", - " n_algo_qubits=n_data_qubits, n_cycles=best_factory.n_cycles(n_magic), phys_err=1e-3\n", + " n_algo_qubits=n_data_qubits, n_cycles=best_factory.n_cycles(n_magic), logical_error_model=err_model\n", ")\n", "\n", "print(f\"distillation error: {distillation_error:.3%}\") # ref: 0.1% per 1e10 Toffolis\n", @@ -104,7 +114,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -118,9 +128,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.8" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/qualtran/surface_code/ui.py b/qualtran/surface_code/ui.py index ca987bcca..1fb258343 100644 --- a/qualtran/surface_code/ui.py +++ b/qualtran/surface_code/ui.py @@ -387,7 +387,7 @@ def create_qubit_pie_chart( 'Magic State Distillation', ] memory_footprint['qubits'] = [ - FastDataBlock.grid_size(int(algorithm.algorithm_qubits)), + FastDataBlock.get_n_tiles(int(algorithm.algorithm_qubits)), multi_factory.footprint(), ] fig = px.pie( @@ -466,7 +466,7 @@ def create_runtime_plot( unit, duration = format_duration(duration) duration_name = f'Duration ({unit})' num_qubits = ( - FastDataBlock.grid_size(int(algorithm.algorithm_qubits)) + FastDataBlock.get_n_tiles(int(algorithm.algorithm_qubits)) + factory.footprint() * magic_counts ) df = pd.DataFrame(