loom_rotated_surface_code.applicator.move_block

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.

loom_rotated_surface_code.applicator.move_block.check_valid_move(occupied_qubits, moving_qubits, direction)[source]

This function checks if the move operation is valid by ensuring that none of the moving qubits will be moved onto an occupied qubit. If any of the moving qubits will be moved onto an occupied qubit, a ValueError is raised.

Parameters:
  • occupied_qubits (tuple[tuple[int, int, int], ...]) – A tuple of qubit coordinates representing “occupied” qubits. Qubits taking part in the move, cannot be moved onto these set of qubits as they are “occupied”.

  • moving_qubits (tuple[tuple[int, int, int], ...]) – A tuple of qubit coordinates representing qubits that will be moved. The last value in each qubit coordinate tuple represents the sub-lattice index of the qubit.

  • direction (Direction | DiagonalDirection) – The direction in which the qubits will be moving.

Raises:

ValueError – If the move is invalid, i.e., if any of the moving qubits will be moved onto an occupied qubit.

loom_rotated_surface_code.applicator.move_block.composite_direction(direction)[source]

For the move operation, the user defines only “right”, “left”, “top” or “bottom”. However, the actual movement of the block is done via 2 diagonal directions. This function returns a tuple of 2 sets of directions based on the user-defined direction.

For e.g. If the user specifies “right”, the actual movement involves qubits moving to the “top right” then “bottom right”. It would return a tuple with a set of directions “right” and “bottom”, and a tuple with the directions “top” and “right”, representing “bottom right” and “top right” respectively.

composite_direction(Direction.RIGHT) -> (DiagonalDirection.TOP_RIGHT, DiagonalDirection.BOTTOM_RIGHT)

Parameters:

direction (Direction) – The direction in which the block is to be moved.

Returns:

A tuple of 2 sets of diagonal directions which together represent the composite direction of movement.

Return type:

tuple[DiagonalDirection, DiagonalDirection]

loom_rotated_surface_code.applicator.move_block.find_swap_then_qec_qubit_initializations(stabilizers, diag_direction, relocation_diag_direction=None)[source]

Find the qubits to initialize for the swap_then_qec operation in the y_wall_out operation context. This is for a subset of stabilizers of the block that are associated with the boundary qubits.

The recipe is as follows for moving towards TOP-RIGHT:

    1. FIND (non-teleporting) ANCILLA QUBIT INITIALIZATIONS:

    For each stabilizer that is NOT a the TOP-RIGHT boundary stabilizer, find the ancilla qubit on the TOP-RIGHT of the initial ancilla qubit and initialize it in the basis corresponding to the stabilizer.

    1. FIND TELEPORTATION QUBIT PAIRS:

    For each stabilizer that is NOT a BOTTOM-LEFT boundary stabilizer, check if the ancilla qubit of the stabilizer is already initialized. If not, initialize it in the basis corresponding to the stabilizer and form a teleportation qubit pair with the data qubit on the BOTTOM-LEFT of the ancilla.

    1. FIND DATA QUBIT INITIALIZATIONS:

    For each stabilizer that is a TOP-RIGHT boundary stabilizer, find the data qubit on the TOP-RIGHT of the ancilla qubit and initialize it in the basis corresponding to the stabilizer.

Say we have the following block annotated by its stabilizers:

            Z
   o --- o --- o
X  |  Z  |  X  |
   o --- o --- o
   |  X  |  Z  |  X
   o --- o --- o
      Z

To perform SWAP-THEN-QEC to move the block diagonally towards the TOP-RIGHT, we need to initialize the qubits in the basis as shown below:

        --- z
   x  |  z  |
o --- o --- o
|  z  |  x  |  z
o --- o --- o --- x
|  x  |  z  |  x
o --- o --- o

Of these, the teleportation qubit pairs can be seen with the numberings below:

        --- z
   x  |  z  |
o --- o --- o
|  1  |  x  |  z
1 --- o --- o --- x
|  2  |  z  |  3
2 --- o --- 3
Parameters:
  • stabilizers (list[Stabilizer]) – The stabilizers of the block.

  • diag_direction (DiagonalDirection) – The diagonal direction that the block is moving.

  • relocation_diag_direction (DiagonalDirection) – The directions to relocate the qubits. If None, the qubits are not relocated.

Return type:

tuple[dict[str, list[tuple[int, ...]]], dict[str, list[tuple[int, ...]]], list[tuple[tuple[int, ...], tuple[int, ...]]]]

Returns:

  • dict[str, list[tuple[int, …]]] – The ancilla qubits to initialize in the X and Z basis.

  • dict[str, list[tuple[int, …]]] – The data qubits to initialize in the X and Z basis.

  • list[tuple[tuple[int, …], tuple[int, …]]] – The teleportation qubit pairs. The first qubit is the ancilla qubit and the second is the data qubit.

loom_rotated_surface_code.applicator.move_block.generate_and_append_block_syndromes_and_detectors(interpretation_step, block, syndrome_measurement_cbits)[source]

Generate and append syndromes and detectors to the interpretation step.

NOTE: This should probably be made into a method of InterpretationStep.

Parameters:
  • interpretation_step (InterpretationStep) – The interpretation step. Note that it may be mutated by generating new channels.

  • block (RotatedSurfaceCode) – The block to which the operation will be applied.

  • syndrome_measurement_cbits (list[tuple[Cbit, ...]]) – The list of syndrome measurement classical bits. It has to correspond to the stabilizers of the block.

Return type:

None

loom_rotated_surface_code.applicator.move_block.generate_syndrome_measurement_circuit_and_cbits(interpretation_step, block, actual_anc_qubit_relocation_vector=(0, 0, 0))[source]

Generate and return the circuit that measures the stabilizers of the block and the list of stabilizer measurements as tuples of Cbits.

Parameters:
  • interpretation_step (InterpretationStep) – The interpretation step. Note that it may be mutated by generating new channels.

  • block (RotatedSurfaceCode) – The block whose stabilizers are to be measured.

  • actual_anc_qubit_relocation_vector (tuple[int, ...], optional) – The vector to the actual ancilla qubit, by default (0, 0, 0)

Return type:

tuple[Circuit, list[tuple[Union[tuple[str, int], Literal[1, 0]], ...]]]

Returns:

  • Circuit – The circuit that performs the measurement of the stabilizers of the block. Note that it’s just the final measurement operations and not the full stabilizer measurement circuit.

  • list[tuple[Cbit, …]] – The list of stabilizer measurements as tuples of Cbits. The order of the list corresponds to the order of the stabilizers in block.stabilizers.

loom_rotated_surface_code.applicator.move_block.generate_teleportation_measurement_circuit_with_updates(interpretation_step, new_block, anc_qubits_to_init, teleportation_qubit_pairs)[source]

Generate the circuit that finalizes the teleportation operation. This includes the measurement of the data qubits and the updating of the necessary stabilizers based on the measurement outcomes.

Parameters:
  • interpretation_step (InterpretationStep) – The interpretation step. Note that it may be mutated by generating new channels and updating stabilizers and logical operators.

  • new_block (RotatedSurfaceCode) – The new block after the diagonal move.

  • anc_qubits_to_init (dict[str, list[tuple[int, ...]]]) – A dictionary mapping each Pauli type to its list of ancilla qubit initializations.

  • teleportation_qubit_pairs (list[tuple[tuple[int, ...], tuple[int, ...]]]) – A list of tuples, each containing a pair of qubits involved in the teleportation operation. The first qubit in each tuple is the ancilla qubit to be corrected, and the second qubit is the data qubit to be measured.

Returns:

The circuit that finalizes the teleportation operation

Return type:

Circuit

loom_rotated_surface_code.applicator.move_block.get_swap_qec_cnots(interpretation_step, new_block, move_diag_direction, stab_schedule_dict, anc_qubit_initialization, data_qubit_initialization)[source]

Generates the circuit for the final step of the swap-then-qec operation. This step moves the data qubits to their final positions where the new_block definition is.

Parameters:
  • interpretation_step (InterpretationStep) – The interpretation step. Note that it may be mutated by generating new channels.

  • new_block (RotatedSurfaceCode) – The new block after the diagonal move.

  • move_diag_direction (DiagonalDirection) – The diagonal direction in which the block is moving.

  • stab_schedule_dict (dict[Stabilizer, DetailedSchedule]) – A dictionary mapping each stabilizer to its detailed schedule.

  • anc_qubit_initialization (dict[str, list[tuple[int, ...]]]) – A dictionary mapping each Pauli type to its list of ancilla qubit initializations.

  • data_qubit_initialization (dict[str, list[tuple[int, ...]]]) – A dictionary mapping each Pauli type to its list of data qubit initializations.

Returns:

The generated circuit for the final step of the swap-then-qec operation.

Return type:

Circuit

loom_rotated_surface_code.applicator.move_block.move_block(interpretation_step, operation, same_timeslice, debug_mode)[source]

Applicator to move a block in a fault tolerant manner based on the MoveBlock operation. The Block will be moved 1-unit in the specified direction by moving twice diagonally. By default, the diagonal moves are chosen using a secondary direction TOP or LEFT.

For example, if the direction is RIGHT, the block will move diagonally upwards to the right in the first syndrome extraction round and diagonally downwards to the right in the second round.

The algorithm is as follows:

  • A.) Valid move check

    • A.1) Check if the qubits required for the block to be moved are available.

  • B.) Shift the block

    • B.1) Shift the block in the specified direction

    • B.2) Update the block history and evolution

    • B.3) Update all the evolutions

    • B.4) Propagate all the updates

  • C.) Circuit generation

    • C.1) Find the qubit initializations required for the swap-then-qec operation

      and create the reset circuit

    • C.2) Find the stabilizer schedules for the new block and generate the cnot

      circuit

    • C.3) Generate the teleportation finalization circuit with necessary updates

      to stabilizers and logical operators

    • C.4) Final measurement of the stabilizers and generation of syndromes

    • C.5) Combine all the circuits into one diagonal move circuit

  • D.) Append necessary information to the interpretation step

    • D.1) Append the circuit to the interpretation step

    • D.2) Update the block history and evolution

    • D.3) Create and append the new syndromes and detectors

  • Repeat steps A, B, C for the second diagonal direction.

  • E.) Final Circuit
    • E.1) Wrap the generated circuits into a single circuit representing the full MoveBlock operation.

If the block is moved to the top:

The syndrome extraction circuits assign the qubits as follows:

  1. The first set of syndrome extraction rounds assigns the qubits as follows:

                a
        x --- x --- x
     a  |  a  |  a  |
        x --- x --- x
        |  a  |  a  |  a
        x --- x --- x
            a
    
    
    where x are data channels and a are ancilla channels.
    

2. The second set of syndrome extraction rounds creates a new set of channels BASED on how the channels are first created, in most cases as ancilla qubits of either the teleport circuits or that of the syndrome extraction rounds during the move.

As such the new set of qubits are assigned as follows:

a     a     a
   x --- x --- x
a  |  a  |  a  |
   x --- x --- x
a  |  a  |  a  |  a
   x --- x --- x
      a

2b. Following step:

      x     x     x
   a --- a --- a
x  |  x  |  x  |  x
   a --- a --- a
   |  x  |  x  |  x
   a --- a --- a     a
      x     x     x
         a

2c. Final Expected Configuration:

               a
      x --- x --- x
   a  |  a  |  a  |
a     x --- x --- x
   a  |  a  |  a  |  a
      x --- x --- x
   a     a     a     a
      x     x     x
         a
Parameters:
  • interpretation_step (InterpretationStep) – The current interpretation step.

  • operation (MoveBlock) – MoveBlock operation description.

Returns:

Interpretation Step after the MoveBlock operation has been applied.

Return type:

InterpretationStep

Raises:

ValueError – If the block is not 2D or if the block cannot be moved in the specified direction.

loom_rotated_surface_code.applicator.move_block.move_block_diagonally_via_swap_qec(interpretation_step, current_block, diag_direction, debug_mode)[source]

Moves the block diagonally in the specified direction using a swap-then-qec procedure.

Parameters:
  • interpretation_step (InterpretationStep) – The current interpretation step.

  • current_block (RotatedSurfaceCode) – The current block to be moved.

  • diag_direction (Direction) – The diagonal direction in which the block is to be moved.

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

Returns:

The new block after the move and the circuit that performs the move.

Return type:

tuple[RotatedSurfaceCode, Circuit]