loom_rotated_surface_code.code_factory.rotated_surface_code

Copyright 2024 Entropica Labs Pte Ltd

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, 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.

class loom_rotated_surface_code.code_factory.rotated_surface_code.RotatedSurfaceCode(*args, **kwargs)[source]

Bases: Block

A sub-class of Block that represents a rotated surface code block. Contains methods to create a rotated surface code block along with properties to access the block’s size, upper left qubit, stabilizers, logical operators, and other relevant information.

property all_boundary_stabilizers: tuple[Stabilizer, ...]

Return the stabilizers associated with any boundary.

boundary_qubits(direction)[source]

Return the data qubits that are part of the specified boundary.

Parameters:

direction (Direction | str) – Boundary (top, bottom, left, or right) for which the data qubits should be returned. If a string is provided, it is converted to a Direction enum.

Returns:

Data qubits that are part of the specified boundary

Return type:

list[tuple[int, …]]

boundary_stabilizers(direction)[source]

Return the stabilizers associated with the given boundary direction.

Return type:

tuple[Stabilizer, ...]

boundary_type(direction)[source]

Return the type of the specified boundary, either X or Z. This assumes that the block is a standard rotated surface code block which is a square block with Y charges at the four corners and X and Z charges at the boundaries.

Note that there are different conventions about when to call a boundary X or Z. We call a boundary X type if it exhibits X Pauli charges. In other words, it is of X type if the stabilizers along the boundary are Z stabilizers.

Parameters:

direction (Direction | str) – Boundary (top, bottom, left, or right) for which the data qubits should be returned. If a string is provided, it is converted to a Direction enum.

Returns:

Type of the boundary, either X or Z

Return type:

str

property bulk_stabilizers: tuple[Stabilizer, ...]

Return the stabilizers not associated with any boundary.

property config_and_pivot_corners: tuple[int, tuple[tuple[int, int, int], ...]]

Classify the Block based on the geometry of its topological corners. Return the config and the topological corners ordered in a specific way that reflects their geometric arrangement.

Type 1: Rectangular config

Four topological corners coincide with 4 geometric corners The list of corners is returned in the order: (top-left, bottom-left, bottom-right, top-right)

Visualized example:

1-------4
|       |
|       |
|       |
2-------3
Type 2: U-config

Block has rectangular shape with size (d, 2d-1) or (2d-1, d) Three of four topological corners coincide with three geometric corners, the last topological corner resides on the middle of the long edge whose ends occupy only one topological corner The list of corners is returned in the order: (long_end, middle_edge, angle, short_end)

Visualized example (can be rotated):

1-------|
|       |
|       2
|       |
3-------4
Type 3: L-config

Block has rectangular shape with size (d, 2d-1) or (2d-1, d) Three of four topological corners coincide with three geometric corners, the last topological corner resides on the middle of the long edge whose ends occupy two topological corners. The list of corners is returned in the order as seen below: (long_end, middle_edge, angle, short_end)

Visualized example (can be rotated):

1-------|
|       |
2       |
|       |
3-------4
Type 4: U-config (phase gate)

Block has rectangular shape with size (d, 2d) or (2d, d) Three of four topological corners coincide with three geometric corners, the last topological corner resides in the middle of the long edge whose ends occupy only one topological corner. Since the length of a long edge is even, there are two qubits near the middle point of the edge. Only support the case where the qubit is further away from the end occupied by a topological corner. The list of corners is returned in the order: (long_end, middle_edge, angle, short_end)

Visualized example (can be rotated):

1-------|
|       |
|       2
|       |
|       |
3-------4

Type 0: Other configs

Returns:

  • int – The configuration type of the block.

  • tuple[tuple[int, int, int], …] – The list of corners in the order specified by the configuration type.

classmethod create(dx, dz, lattice, unique_label=None, position=(0, 0), x_boundary=Orientation.HORIZONTAL, weight_2_stab_is_first_row=True, weight_4_x_schedule=None, logical_x_operator=None, logical_z_operator=None, skip_validation=False)[source]

Create a Block object for a rotated surface code block. The orientation of the block (i.e. where which boundaries are) and where the weight-2 stabilizers are can be controlled with the x_boundary and weight_2_stab_is_first_row argument. By default, the top row and the left column are chosen as the logical operators. Their pauli string and whether they belong to the logical Z or X operator depends on the orientation of the boundaries.

The coordinates used for data qubits are the following (here as an example for a d=3 rotated surface code, with x_boundary=Orientation.H and weight_2_stab_is_first_row=True):

..code-block:

                   Z
  (0,0) --- (1,0) --- (2,0)
    |         |         |
X   |    Z    |    X    |
    |         |         |
  (0,1) --- (1,1) --- (2,1)
    |         |         |
    |    X    |    Z    |  X
    |         |         |
  (0,2) --- (1,2) --- (2,2)
         Z
Parameters:
  • dx (int) – Size of the block in the horizontal direction

  • dz (int) – Size of the block in the vertical direction

  • lattice (Lattice) – Lattice on which the block is defined. The qubit indices depend on the type of lattice.

  • unique_label (str, optional) – Label for the block. It must be unique among all blocks in the initial Eka. If no label is provided, a unique label is generated automatically using the uuid module.

  • position (tuple[int, ...], optional) – Position of the top left corner of the block on the lattice, by default (0, 0)

  • x_boundary (Orientation, optional) – Specifies whether the X boundaries are horizontal (Orientation.HORIZONTAL), i.e. going from left to right, or vertical (Orientation.V), i.e. going from top to bottom. The X boundary is the boundary that exhibits X Pauli charges. In other words it is the boundary with 2-body Z stabilizers. By default Orientation.HORIZONTAL.

  • weight_2_stab_is_first_row (bool, optional) – Specifies whether the top most weight-2 stabilizer at the left boundary is in the first row (if True) or in the second row (if False), by default True

  • weight_4_x_schedule (FourBodySchedule, optional) – Schedule for measuring the XXXX stabilizer, by default None. If None is provided, the schedule is calculated from the orientation of the X boundary. E.g. if x_boundary is Orientation.HORIZONTAL, the schedule is set to FourBodySchedule.N. The default scheme is described in https://arxiv.org/abs/1404.3747 III, B. In the example above, weight_4_x_schedule is FourBodySchedule.N, this is equivalent to measure the upper right XXXX stabilizer in the order (2,0) -> (2,1) -> (1,0) -> (1,1).

  • logical_x_operator (PauliOperator | None, optional) – Logical X operator. If None is provided, by default the top row or the left column is chosen (depending on the orientation of the block as specified by the x_boundary and weight_2_stab_is_first_row parameter)

  • logical_z_operator (PauliOperator | None, optional) – Logical Z operator. If None is provided, by default the top row or the left column is chosen (depending on the orientation of the block as specified by the x_boundary and weight_2_stab_is_first_row parameter)

  • skip_validation (bool, optional) – Skip validation of the block object, by default False.

Returns:

Block object for a rotated surface code block

Return type:

Block

static find_padding(boundary, schedule)[source]

Finds the padding indices for the two body stabilizers. Padding indices are used to indicate empty time steps in the syndrome circuits. This allows to standardize the size of syndrome circuits for the rotated surface code.

Parameters:
  • boundary (Direction) –

    Type of boundary for the surface code can be LEFT, RIGHT, TOP, or

    BOTTOM

  • schedule (FourBodySchedule) –

    Schedule for measuring the four body stabilizers, we can deduce the two

    body schedule from this.

Returns:

Padding indices.

Return type:

tuple[int, int]

static generate_syndrome_circuit(pauli, padding, name)[source]

Generates a syndrome circuit for a given Pauli string. The syndrome circuits generated are all the same size, where padding indices indicate where to add empty time steps.

Parameters:
  • pauli (str) – Pauli string associated the stabilizer

  • padding (tuple[int, int] | None) – Padding indices for the two body stabilizers. Padding indices are used to locate empty spaces in the syndrome circuits.

  • name (str) – Name of the syndrome circuit

Returns:

Syndrome circuit for the Pauli string

Return type:

SyndromeCircuit

static generate_weight2_stabs(pauli, initial_position, num_stabs, orientation, is_bottom_or_right)[source]

Generate the list of all weight-2 stabilizers along one of the four boundaries. Note that the schedule for measuring the weight-4 stabilizers does not change the order in which we specify the weight-2 stabilizers. For stabilizers along the right and bottom boundaries, the stabilizers are generated differently. The stabilizers along the right and bottom boundary have the coordinates of the ancilla qubits shifted by (1, 0) and (0, 1) respectively.

Parameters:
  • pauli (str) – Pauli string of the stabilizers

  • initial_position (tuple[int, int]) – Initial position where the chain of weight-2 stabilizers should start

  • num_stabs (int) – Number of weight-2 stabilizers to generate along this boundary

  • orientation (Orientation) – Orientation of the boundary, either HORIZONTAL or VERTICAL

  • is_bottom_or_right (bool) – If True, the stabilizers are along the bottom or right boundaries, this means their ancilla qubit is ‘outside’ of the block geometry. If False, the stabilizers are along the top or left boundaries.

Returns:

List of weight-2 stabilizers along the specified boundary

Return type:

list[Stabilizer]

static generate_weight4_stabs(dx, dz, pauli, schedule, start_in_top_left_corner, initial_position=(0, 0))[source]

Generate the list of all weight-4 stabilizers of a rotated surface code block of the given type (= pauli string).

Parameters:
  • dx (int) – Distance in the horizontal direction. If dx=3, there will be 2 weight-4 stabilizers created in the horizontal direction.

  • dz (int) – Distance in the vertical direction. If dz=3, there will be 2 weight-4 stabilizers created in the vertical direction.

  • pauli (str) – Pauli string of the stabilizers

  • start_in_top_left_corner (bool) – If True, the first stabilizer will start in the top left corner and then follow the alternating checkerboard pattern. If False, it will be exactly the opposite covering of the checkerboard pattern.

  • schedule (FourBodySchedule) – Schedule for measuring the four body stabilizers, see https://arxiv.org/abs/1404.3747, III, B. for more details.

  • initial_position (tuple[int, int], optional) – Initial position where the chain of weight-4 stabilizers should start, by default (0, 0)

Returns:

List of weight-4 stabilizers of the specified type for the rotated surface code

Return type:

list[Stabilizer]

property geometric_corners: tuple[tuple[int, ...], ...]

Return the coordinates of the geometric corners of the block. The geometric corners that can be detected are qubits that may be the single most: - top-left qubit - top-right qubit - bottom-left qubit - bottom-right qubit - right-qubit - bottom-qubit - left-qubit - top-qubit

get_corner_from_direction(which_corner)[source]

Get the coordinates of the qubit at the specified corner of the block.

Return type:

tuple[int, int, int]

get_shifted_equivalent_logical_operator(initial_operator, new_upleft_qubit)[source]

Shifts the initial operator to a valid operator in the block that contains new_upleft_qubit. NOTE: this function currently assumes that the block is a square rotated surface code block with a single logical X and Z operator.

Parameters:
  • initial_operator (PauliOperator) – Initial logical operator for which the equivalent logical operator in the block should be found.

  • new_upleft_qubit (tuple[int, ...]) – New top left qubit of the operator in the block.

Returns:

Equivalent logical operator in the block and the stabilizers that are required to go from the initial to the new operator.

Return type:

tuple[PauliOperator, tuple[Stabilizer, …]]

Raises:
  • NotImplementedError – If the block has more than one logical X or Z operator.

  • ValueError – If the new upleft qubit is not part of the data qubits of the block.

  • ValueError – If the initial operator is not one of the logical operators of the block.

  • ValueError – If the new upleft qubit is not part of the correct boundary.

  • ValueError – If the shift vector has more than a single non-zero dimension (ill defined logical operators to begin with).

property is_horizontal: bool

Return True if the horizontal size is larger than the vertical size.

property is_vertical: bool

Return True if the vertical size is larger than the horizontal size.

property orientation: Orientation | None

Return the orientation of the block. If the block is square, return None.

rename(name)[source]

Return a copy of the Block with the new name.

Return type:

RotatedSurfaceCode

shift(position, new_label=None)[source]

Return a copy of the Block where all qubit coordinates are shifted by a given position.

Parameters:
  • position (tuple[int, ...]) – Vector by which the block should be shifted

  • new_label (str | None, optional) – New label for the block. If None, the same label is used.

Returns:

A new Block with the shifted qubit coordinates.

Return type:

Block

property size: tuple[int, int]

Return the size of the block in the horizontal and vertical direction.

stabilizer_to_circuit: dict[str, str] = FieldInfo(annotation=dict[str, str], required=False, default_factory=dict, validate_default=True)
property stabilizers_labels: dict[str, dict[str, tuple[int, ...]]]

Builds a dictionary associating stabilizers, via their uuid, with a set of labels defined through a dictionary. Inside Block, this is generically populated with the space coordinates of the stabilizer check, corresponding to the ancilla which measures each stabilizer.

This functionality can be leveraged to later provide these labels to Syndromes and Detectors associated with a given Stabilizer.

Returns:

Dictionary associating stabilizer uuids with their labels.

Return type:

dict[str, dict[str, tuple[int, …]]]

syndrome_circuits: tuple[SyndromeCircuit, ...] = FieldInfo(annotation=tuple[SyndromeCircuit, ...], required=False, default_factory=tuple, validate_default=True)
property topological_corners: tuple[tuple[int, ...], ...]

Return the coordinates of the topological corners of the block.

unique_label: str = FieldInfo(annotation=str, required=False, default_factory=<lambda>)
property upper_left_4body_stabilizer: Stabilizer

Return the 4-body stabilizer associated with the upper left qubit.

property upper_left_qubit: tuple[int, ...]

Return the qubit with the smallest coordinates in the block.

uuid: str = FieldInfo(annotation=str, required=False, default_factory=<lambda>, validate_default=True)
property weight_2_stab_is_first_row: bool

Return whether the top most weight-2 stabilizer at the left boundary is in the first row.

property weight_4_x_schedule: FourBodySchedule

Return the schedule for measuring the XXXX stabilizer.

property weight_4_z_schedule: FourBodySchedule

Return the schedule for measuring the ZZZZ stabilizer.

property x_boundary: Orientation

Return the orientation of the X boundary.