loom.interpreter.interpretation_step
Copyright (c) Entropica Labs Pte Ltd 2025.
Use, distribution and reproduction of this program in its source or compiled form is prohibited without the express written consent of Entropica Labs Pte Ltd.
- class loom.interpreter.interpretation_step.InterpretationStep(*args, **kwargs)[source]
Bases:
objectThe InterpretationStep class stores all relevant information which was generated during interpretation up to the Operation which is currently interpreted. In every interpretation step, the old InterpretationStep instance is replaced with an updated instance. After all Operations have been interpreted, the last InterpretationStep instance contains the final output.
NOTE on mutability: During the interpretation of an EKA, there is a lot of data generated and modified which is stored inside the InterpretationStep objects. Having the InterpretationStep dataclass mutable makes it a lot easier to modify the data during interpretation. Therefore many of the convenience methods here have side effects on InterpretationStep. To make these side effects explicit, those methods with side effects have the suffix _MUT in their name. This follows the Julia convention where functions with side effects have a
!at the end of their name.NOTE: The operations implemented inside the applicators are not pure functions, they take the previous InterpretationStep as an input and returning an updated InterpretationStep, effectively emulating that behavior. Make sure to always keep track of the InterpretationStep you are currently working on, since it is updated with every operation.
- Parameters:
intermediate_circuit_sequence (tuple[tuple[Circuit, ...], ...]) – The circuit implementing all Operation s which have been interpreted until now. It consists of a tuple of timeslices, where each timeslice is a tuple of Circuit objects. They can be composite circuits. At the final step, this is used to generate final_circuit.
final_circuit (Circuit | None) – The final circuit object which is generated after interpreting all operations. This is the circuit which is used for the final output of the interpretation, it is generated automatically by interpreting all operations.
block_history (tuple[tuple[Block, ...], ...]) – A history of block configurations. The last element in the tuple is the current configuration of blocks. With the interpretation of every Operation a new tuple of blocks is added to this block_history field. While mostly only the last configuration of blocks is relevant, the whole history is stored which might be useful for plotting.
syndromes (tuple[Syndrome, ...]) – A tuple of Syndrome`s which are created due to all syndrome extraction cycles up to the `Operation which is currently interpreted.
detectors (tuple[Detector, ...]) – A tuple of Detector`s which are created due to all syndrome extraction cycles up to the `Operation which is currently interpreted.
logical_observables (tuple[LogicalObservable, ...]) – A tuple of LogicalObservable s which were measured until now.
stabilizer_evolution (dict[str, tuple[str, ...]]) – Keeps track of which stabilizers transformed into which other stabilizers due to operations such as shrink or split. The dictionary is a FINAL-to-INITIAL mapping. In most cases both key and value will be a single string and there is a 1:1 mapping from an old stabilizer to a new stabilizer. If there is a case where multiple stabilizers are combined into a single stabilizer, the value will be a tuple of strings. Conversely, if a single stabilizer is split into multiple stabilizers, two keys would be associated with the same value. E.g. for a split we match new_stab1.uuid to (old_stab.uuid,) and new_stab2.uuid to (old_stab.uuid,). For a situation where we merge two stabilizers, we match merged_stab.uuid to (old_stab1.uuid, old_stab.uuid) .
logical_x_evolution (dict[str, tuple[str, ...]]) – Keeps track of which logical X operator(s) transformed into which other logical X operator(s) due to operations such as shrink or split and eventual stabilizer(s) required to go from one to the next. The dictionary is a FINAL-to-INITIAL mapping. E.g. for a split we match split_x_op1.uuid to (old_x_op.uuid,) and split_x_op2.uuid to (old_x_op.uuid,). For a shrink that moved the X operator using adjacent stabilizers, we match new_x_op.uuid to (old_x_op.uuid, stab1.uuid, stab2.uuid).
logical_z_evolution (dict[str, tuple[str, ...]]) – Keeps track of which logical Z operator(s) transformed into which other logical Z operator(s) due to operations such as shrink or split and eventual stabilizer(s) required to go from one to the next. The dictionary is a FINAL-to-INITIAL mapping. E.g. for a split we match split_z_op1.uuid to (old_z_op.uuid,) and split_z_op2.uuid to (old_z_op.uuid,). For a shrink that moved the Z operator using adjacent stabilizers, we match new_z_op.uuid to (old_z_op.uuid, stab1.uuid, stab2.uuid).
block_evolution (dict[str, tuple[str, ...]]) – Keeps track of which block(s) transformed into which other block(s) due to operations such as merge and split. If there is a 1:1 mapping between and old block and a new block (e.g. due to renaming), the value will be a tuple containing a single string. If one block is split into two blocks, two keys will be associated to the same value that is a tuple containing a single string. If two blocks are merged into a single block, the key will be a single string and the value will be a tuple of two strings. E.g. for a merge, we match merged_block.uuid to (block1.uuid, block2.uuid).
block_qec_rounds (dict[str, int]) – A dictionary storing for every block id how many syndrome extraction rounds have been performed on this block. This is needed for creating new Syndrome and Detector objects which have a round attribute, specifying the syndrome extraction round of the block in which they were measured.
cbit_counter (dict[str, int]) – A dictionary storing how many measurements have been performed and stored in each classical register. The keys are the labels of the classical registers which are used as the first element in Cbit.
block_decoding_starting_round (dict[str, int]) – A dictionary storing for every block the round from which the decoding of this block should start the next time real-time decoding is performed. E.g. if we encounter a non-Clifford gate on a block at time t, we need to decode until this time t. Then in this dictionary, we store that the next decoding round has to include detectors up to time t+1.
logical_x_operator_updates (dict[str, tuple[Cbit, ...]]) – A dictionary storing for every logical X operator, the measurements (in the form of Cbits) which need to be taken into account for updating the Pauli frame of this logical operator once this operator is measured. Elements will be added here when some of the data qubits of the respective logical operator are measured, e.g. in a shrink or split operation. In this case, these measurements lead to a change of pauli frame and need to be included in the next readout of this operator. This is also needed for real-time decoding. The values can be accessed via logical_x_operator_updates[logical_x.uuid]. E.g. for a shrink of length 2 we match new_x_op.uuid to (cbit1, cbit2,).
logical_z_operator_updates (dict[str, tuple[Cbit, ...]]) – A dictionary storing for every logical Z operator, the measurements (in the form of Cbits) which need to be taken into account for updating the Pauli frame of this logical operator once this operator is measured. Elements will be added here when some of the data qubits of the respective logical operator are measured, e.g. in a shrink or split operation. In this case, these measurements lead to a change of pauli frame and need to be included in the next readout of this operator. This is also needed for real-time decoding. The values can be accessed via logical_z_operator_updates[logical_x.uuid]. E.g. for a shrink of length 2 we match new_z_op.uuid to (cbit1, cbit2,).
stabilizer_updates (dict[str, tuple[Cbit, ...]]) – A dictionary storing updates for stabilizers which need to be included when the stabilizer is measured the next time. Elements will be added here when some of the data qubits of the respective stabilizer are measured (in other words when the weight of the stabilizer is reduced), e.g. in a shrink or split operation. The keys of the dictionary are uuids of stabilizers. E.g. for a shrink that changes a weight 4 stabilizer to a weight 2 stabilizer we match new_stab.uuid to (cbit1, cbit2). CAUTION: Some applicators may pop the entries from the stabilizer_updates field of the interpretation step to compute corrections. This may cause issues in the future if the information in this field also needs to be accessed somewhere else.
channel_dict (dict[str, Channel]) – A dictionary storing all channels which have been created during the interpretation. The keys are the labels of the channels (which are either the qubit coordinates or the Cbit tuple). The values are the Channel objects. Only one Channel is created per qubit. Measurements are associated to individual channels. I.e. for every Cbit, there is a separate Channel object.
is_frozen (bool) – A boolean flag, indicating whether the InterpretationStep is frozen. If it is set to True (frozen), calling methods which mutate the InterpretationStep will raise an exception. Defaults to False.
-
block_decoding_starting_round:
dict[str,int] = FieldInfo(annotation=dict[str, int], required=False, default_factory=dict, validate_default=True)
-
block_evolution:
dict[str,tuple[str,...]] = FieldInfo(annotation=dict[str, tuple[str, ...]], required=False, default_factory=dict, validate_default=True)
-
block_history:
tuple[tuple[Block,...],...] = FieldInfo(annotation=tuple[tuple[Block, ...], ...], required=False, default_factory=tuple, validate_default=True)
-
block_qec_rounds:
dict[str,int] = FieldInfo(annotation=dict[str, int], required=False, default_factory=dict, validate_default=True)
-
cbit_counter:
dict[str,int] = FieldInfo(annotation=dict[str, int], required=False, default_factory=dict, validate_default=True)
-
channel_dict:
dict[str,Channel] = FieldInfo(annotation=dict[str, Channel], required=False, default_factory=dict, validate_default=True)
-
detectors:
tuple[Detector,...] = FieldInfo(annotation=tuple[Detector, ...], required=False, default_factory=tuple, validate_default=True)
- get_all_syndromes(stab_id, block_id)[source]
Returns all syndromes associated with a given stabilizer id.
- Parameters:
stab_id (str) – Stabilizer uuid to search for.
block_id (str) – block uuid to search for.
- Returns:
List of all syndromes associated with the given stabilizer and block id.
- Return type:
list[Syndrome]
- get_block(label)[source]
Get the block with the given label from the current block configuration.
- Parameters:
label (str) – Unique label of the block
- Returns:
Block with the given label
- Return type:
- get_prev_syndrome(stabilizer_id, block_id, current_round=None)[source]
Finds the latest syndrome for a given stabilizer_id. If current_round is given, this function returns the latest syndrome for the associated stabilizer such that the round is less than current_round. If None is given, the latest syndrome is returned.
- Parameters:
stabilizer_id (str) – Stabilizer uuid to search for.
block_id (str) – block uuid to search for.
current_round (int | None, optional) – Round to compare to, by default None
- Returns:
The latest syndrome for the given stabilizer_id, block_id and current_round. Returns an empty list if no Syndrome is found.
- Return type:
list[Syndrome]
-
intermediate_circuit_sequence:
tuple[tuple[Circuit,...],...] = FieldInfo(annotation=tuple[tuple[Circuit, ...], ...], required=False, default_factory=tuple, validate_default=False)
-
is_frozen:
bool= False
-
logical_measurements:
dict[LogicalMeasurement,tuple[Union[tuple[str,int],Literal[1,0]],...]] = FieldInfo(annotation=dict[LogicalMeasurement, tuple[Union[tuple[str, int], Literal[1, 0]], ...]], required=False, default_factory=dict, validate_default=True)
-
logical_observables:
tuple[LogicalObservable,...] = FieldInfo(annotation=tuple[LogicalObservable, ...], required=False, default_factory=tuple, validate_default=True)
-
logical_x_evolution:
dict[str,tuple[str,...]] = FieldInfo(annotation=dict[str, tuple[str, ...]], required=False, default_factory=dict, validate_default=True)
-
logical_x_operator_updates:
dict[str,tuple[Union[tuple[str,int],Literal[1,0]],...]] = FieldInfo(annotation=dict[str, tuple[Union[tuple[str, int], Literal[1, 0]], ...]], required=False, default_factory=dict, validate_default=True)
- property logical_x_operators_dict: dict[str, PauliOperator]
Return a dictionary of logical X operators with logical operator uuid as keys.
-
logical_z_evolution:
dict[str,tuple[str,...]] = FieldInfo(annotation=dict[str, tuple[str, ...]], required=False, default_factory=dict, validate_default=True)
-
logical_z_operator_updates:
dict[str,tuple[Union[tuple[str,int],Literal[1,0]],...]] = FieldInfo(annotation=dict[str, tuple[Union[tuple[str, int], Literal[1, 0]], ...]], required=False, default_factory=dict, validate_default=True)
- property logical_z_operators_dict: dict[str, PauliOperator]
Return a dictionary of logical Z operators with logical operator uuid as keys.
- retrieve_cbits_from_stabilizers(stabs_required, current_block)[source]
Retrieve the cbits associated with the most recent syndrome extraction of the stabilizers required to move the logical operator.
- Parameters:
stabs_required (tuple[Stabilizer, ...]) – Stabilizers required to update the logical operator.
current_block (Block) – Current block in which the stabilizers were measured.
- Returns:
Cbits associated with the measurement of the logical operator displacement.
- Return type:
tuple[Cbit, …]
-
stabilizer_evolution:
dict[str,tuple[str,...]] = FieldInfo(annotation=dict[str, tuple[str, ...]], required=False, default_factory=dict, validate_default=True)
-
stabilizer_updates:
dict[str,tuple[Union[tuple[str,int],Literal[1,0]],...]] = FieldInfo(annotation=dict[str, tuple[Union[tuple[str, int], Literal[1, 0]], ...]], required=False, default_factory=dict, validate_default=True)
- property stabilizers_dict: dict[str, Stabilizer]
Return a dictionary of stabilizers with stabilizer uuid as keys.