loom_rotated_surface_code.applicator.utilities

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.applicator.utilities.DetailedSchedule(*values)[source]

Bases: Enum

Assumptions made (The 4-body stabilizer looks like this): 1 – 2 | | 3 – 4

For N-type schedule, if the first qubit is 1. (i.e. N1) The schedule will be: 1 -> 3 -> 2 -> 4

For Z-type schedule, if the first qubit is 4. (i.e. Z4) The schedule will be: 4 -> 3 -> 2 -> 1

The key of the Enum is the schedule type and first qubit in the schedule. (i.e. N1, N2, …) The value is a tuple of qubit indices in the order of the schedule. (i.e. [1, 3, 2, 4]: tuple[int, int, int, int])

NOTE: If the Block was created by the RotatedSurfaceCode.create() method, the schedules will be N2 or Z2, for the X(Z) or Z(X) Stabilizer.

Code example: `python schedule = DetailedSchedule.N1 type(schedule)  # <enum 'DetailedSchedule'> type(schedule.value)  # <class 'tuple'> `

N1 = (1, 3, 2, 4)
N2 = (2, 4, 1, 3)
N3 = (3, 1, 4, 2)
N4 = (4, 2, 3, 1)
Z1 = (1, 2, 3, 4)
Z2 = (2, 1, 4, 3)
Z3 = (3, 4, 1, 2)
Z4 = (4, 3, 2, 1)
classmethod from_schedule_and_direction(schedule, starting_qubit_direction)[source]

Create a DetailedSchedule from a FourBodySchedule and a starting qubit direction.

Return type:

DetailedSchedule

get_stabilizer_qubits(stab, boundary_direction=None)[source]

For a specific stabilizer and a specific schedule, return the qubits in the order they should be entangled. The qubits are returned in the order of the schedule. The qubits that are not in the schedule are set to None.

Parameters:
  • stab (Stabilizer) – The stabilizer for which the qubits are to be determined.

  • boundary_direction (Direction) – The direction of the boundary. This is required for weight-2 stabilizers.

Returns:

The qubits in the order they should be entangled. The qubits that are not in the schedule are set to None.

Return type:

list[tuple[int, int, int]]

invert_vertically()[source]

Inverts the schedule vertically. For example, N1 = (1, 3, 2, 4) is transformed into N2 = (2, 4, 1, 3).

Returns:

The inverted schedule.

Return type:

DetailedSchedule

is_N()[source]

Checks if the schedule is an N-type schedule.

Returns:

True if the schedule is an N-type schedule, False otherwise.

Return type:

bool

is_Z()[source]

Checks if the schedule is a Z-type schedule.

Returns:

True if the schedule is a Z-type schedule, False otherwise.

Return type:

bool

rotate_ccw_90()[source]

Rotates the schedule counter-clockwise by 90 degrees. For example, N1 = (1, 3, 2, 4) is transformed into Z3 = (3, 4, 1, 2).

Returns:

The rotated schedule.

Return type:

DetailedSchedule

loom_rotated_surface_code.applicator.utilities.add_vector(qubit, direction, length)[source]

Add a direction vector to a qubit coordinate scaled by length. Used to calculate the new position of a corner after moving it.

Return type:

tuple[int, int, int]

loom_rotated_surface_code.applicator.utilities.create_new_syndrome_circuits_with_known_schedules(rsc_block, non_triangle_x_schedule, non_triangle_z_schedule, triangle_x_schedule, triangle_z_schedule, starting_qubit_diag_directions)[source]

Create the syndrome extraction circuits for each stabilizer in the input block based on the schedules provided in the input. The data qubits of each stabilizer are ordered according to the schedule and the starting qubit direction.

Parameters:
  • rsc_block (RotatedSurfaceCode) – The rotated surface code block.

  • non_triangle_x_schedule (FourBodySchedule) – Schedule for X-type stabilizers in the non-triangle part.

  • non_triangle_z_schedule (FourBodySchedule) – Schedule for Z-type stabilizers in the non-triangle part.

  • triangle_x_schedule (FourBodySchedule | None) – Schedule for X-type stabilizers in the triangle part. None if there is no triangle part.

  • triangle_z_schedule (FourBodySchedule | None) – Schedule for Z-type stabilizers in the triangle part. None if there is no triangle part.

  • starting_qubit_diag_directions (DiagonalDirection) – The diagonal direction of the starting data qubit for each syndrome extraction circuit.

Returns:

A tuple containing: - A tuple of generated syndrome extraction circuits. - A dictionary mapping stabilizer UUIDs to their corresponding syndrome circuit UUIDs.

Return type:

tuple[tuple[SyndromeCircuit, …], dict[str, str]]

loom_rotated_surface_code.applicator.utilities.direction_to_coord(direction, sublattice_index=None)[source]

Converts a direction to a coordinate vector. This assumes the coordinates are in 3-dimensions with the last coordinate being a sub-lattice index. The sub-lattice index of the current coordinate is also required for diagonal movements if the qubit is moved to a different sub-lattice.

Parameters:
  • direction (Direction | DiagonalDirection) – The direction in which the block is to be moved.

  • sublattice_index (Optional[int]) – The sub-lattice index of the current coordinate. This should be defined for diagonal movements where the qubit is moved to a different sub-lattice. If it’s a diagonal movement but on the same sub-lattice, this should be None.

Returns:

The coordinate vector representing the direction in which the block is to be moved.

Return type:

tuple[int, int, int]

Raises:

ValueError – If the direction is not of type Direction or set of Directions of size 2. If the sub-lattice index is not an integer or None for diagonal movements. If the direction is not a valid direction.

loom_rotated_surface_code.applicator.utilities.find_detailed_schedules(rsc_block, starting_direction)[source]

Find the detailed schedules for each stabilizer in the input block. The detailed schedule is determined by the schedule type (N or Z) and the starting qubit direction. We can expand it by refactoring the code to distinguish between triangle and non-triangle stabilizers with a function.

Parameters:
  • rsc_block (RotatedSurfaceCode) – The rotated surface code block.

  • starting_direction (DiagonalDirection) – The diagonal direction of the starting data qubit for each syndrome extraction circuit.

Returns:

A dictionary mapping each stabilizer to its corresponding detailed schedule.

Return type:

dict[Stabilizer, DetailedSchedule]

loom_rotated_surface_code.applicator.utilities.find_relative_diagonal_direction(from_qubit, to_qubit)[source]

Find the relative diagonal direction from qubit_1 to qubit_2. If two qubits have the same horizontal coordinate, the horizontal direction is set to Direction.LEFT by default. If two qubits have the same vertical coordinate, the vertical direction is set to Direction.TOP by default.

Parameters:
  • from_qubit (tuple[int, ...]) – The starting qubit

  • to_qubit (tuple[int, ...]) – The final qubit

Return type:

DiagonalDirection

loom_rotated_surface_code.applicator.utilities.find_schedules(rsc_block)[source]

Determine schedule for stabilizers of the block.

For type 1 and 2 corner configuration (rectangle and U-shape), schedules can be inferred from boundary type of the short edge connecting two topological corners.

Example:

(type 1)
1-------4
|       |
|       |
|       |
2-------3

(type 2)
1-------|
|       |
|       2
|       |
3-------4

For type 3 corner configuration (L-shape), draw a diagonal line through the middle-edge topological corner and the geometric corner that is not occupied by a topological corner. This line divides the block into two parts, one triangle part and one non-triangle part. Return schedules for X and Z-type stabilizers in these parts.

Example: the line is drawn through topological corner 2 and geometric corner x:

(type 3)
1-------x
|       |
2       |
|       |
3-------4

For type 4 corner configuration (U-shape phase gate), draw a diagonal line through the middle-edge topological corner towards the direction of the angle topological corner. This line divides the block into two parts, one triangle part and one non-triangle part. Return schedules for X and Z-type stabilizers in these parts.

Example: the line is drawn through topological corner 2 and geometric corner x:

(type 4)
1-------.
|       |
|       2
|       |
x       |
3-------4

The algorithm is the following:

  • A.) Find the boundary type of the short boundary connecting two topological corners. For type 1, pick any short edge.

  • B.) Find schedules

    • B.1.) Boundary type is of opposite Pauli type to the logical operator running along the boundary. (e.g. boundary_type = “X” means logical Z running along the boundary)

    • B.2.) For type 1 (rectangle) and type 2 (U shape), the opposite short edge has the same Pauli type. The schedule of stabilizers with the same Pauli type as the short edge is determined so that the propagation of the opposite Pauli type is perpendicular to the short edge. The schedule of the-opposite-type stabilizers is the opposite schedule of the above schedule.

    • B.3.) For type 3 (L shape), the opposite short edge has the opposite Pauli type. Inside the triangle, the schedule for stabilizers with the same type as the short edge is determined. Then the schedule for the other type stabilizers inside the triangle is the opposite schedule. Outside the triangle, the schedules are the opposite schedules of the same stabilizer type.

    • B.4.) For type 4 (U-shape phase gate), inside the triangle, the schedule for stabilizers with the same type as the short edge is determined. Then the schedule for the other type of stabilizers is the opposite schedule. Outside the triangle, the schedules of both type stabilizers follow the schedule for stabilizers with the same type as the short edge inside the triangle.

Return type:

tuple[FourBodySchedule, FourBodySchedule, FourBodySchedule | None, FourBodySchedule | None]

Returns:

  • FourBodySchedule – The schedule type of X-stabilizer in the non-triangle part (for 1,2,3, config).

  • FourBodySchedule – The schedule type of Z-stabilizer in the non-triangle part (for 1,2,3, config).

  • FourBodySchedule | None – The schedule type of X-stabilizer in the triangle part (for type 3 config). None for other type of config.

  • FourBodySchedule | None – The schedule type of Z-stabilizer in the triangle part (for type 3 config). None for other type of config.

loom_rotated_surface_code.applicator.utilities.find_stabilizer_position(rsc_block, config, pivot_corners, stab, is_horizontal)[source]

Find stabilizer position relative to the triangle partition (in type 3 configuration)

Parameters:
  • rsc_block (RotatedSurfaceCode) – The initial block

  • config (int) – Corner configuration

  • pivot_corners (tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...], tuple[int, ...]]) – tuple[tuple[int, …], tuple[int, …], tuple[int, …], tuple[int, …]] Four topological corners

  • stab (Stabilizer) – The input stabilizer

  • is_horizontal (bool) – True if the long edge of the block is horizontal

Returns:

True if the stabilizer is inside triangular part (if any) Direction of the boundary if the input stabilizer is a weight-2 stabilizer

Return type:

tuple[bool, Direction | None]

loom_rotated_surface_code.applicator.utilities.generate_syndrome_extraction_circuits(rsc_block, starting_qubit_diagonal_direction)[source]

Given a rotated surface code block, generate syndrome extraction circuits for each stabilizer based on the starting diagonal direction. The generated syndrome circuits should lead to a fault-tolerant behavior if used appropriately (with an appropriate starting_qubit_diagonal_direction).

Parameters:
  • rsc_block (RotatedSurfaceCode) – A rotated surface code block.

  • starting_qubit_diagonal_direction (DiagonalDirection) – The diagonal direction of the starting data qubit for each syndrome extraction circuit.

Returns:

A tuple containing:

  • A tuple of generated syndrome extraction circuits.

  • A dictionary mapping stabilizer UUIDs to their corresponding syndrome circuit UUIDs.

Return type:

tuple[tuple[SyndromeCircuit, …], dict[str, str]]

loom_rotated_surface_code.applicator.utilities.shift_block_towards_direction(rsc_block, direction, debug_mode)[source]

Move the input block by one unit towards the input direction.

Parameters:
  • rsc_block (RotatedSurfaceCode) – The rotated surface code block to be moved.

  • direction (Direction | DiagonalDirection) – The direction towards which the block is moved.

  • debug_mode (bool) – If True, skip validation when creating the new block.

Return type:

tuple[RotatedSurfaceCode, dict[str, tuple[str, ...]], dict[str, tuple[str, ...]], dict[str, tuple[str, ...]]]

Returns:

  • RotatedSurfaceCode – The moved rotated surface code block.

  • dict[str, tuple[str, …]] – A dictionary mapping old stabilizer UUIDs to new stabilizer UUIDs.

  • dict[str, tuple[str, …]] – A dictionary mapping old logical X operator UUIDs to new logical X operator UUIDs.

  • dict[str, tuple[str, …]] – A dictionary mapping old logical Z operator UUIDs to new logical Z operator UUIDs.

loom_rotated_surface_code.applicator.utilities.update_qubit_coords(input_qubit_coords, direction)[source]

This function updates the coordinates of the qubits based on the direction of movement.

Return type:

tuple[int, int, int]