diff --git a/src/qce_circuit/connectivity/generic_gate_sequence.py b/src/qce_circuit/connectivity/generic_gate_sequence.py index d3db674..1c58043 100644 --- a/src/qce_circuit/connectivity/generic_gate_sequence.py +++ b/src/qce_circuit/connectivity/generic_gate_sequence.py @@ -1,9 +1,9 @@ # ------------------------------------------- # Module containing interface and implementation of generic (Surface17) gate sequences. # ------------------------------------------- -from abc import ABCMeta +from abc import ABCMeta, abstractmethod from typing import List, Union -from qce_circuit.utilities.custom_exceptions import ElementNotIncludedException +from qce_circuit.utilities.custom_exceptions import ElementNotIncludedException, InterfaceMethodException from qce_circuit.utilities.array_manipulation import unique_in_order from qce_circuit.connectivity.intrf_channel_identifier import ( IQubitID, @@ -26,7 +26,16 @@ class IGenericSurfaceCodeLayer(ISurfaceCodeLayer, IGateSequenceLayer, metaclass= """ Interface class, combining ISurfaceCodeLayer and IGateSequenceLayer. """ - pass + + # region Interface Methods + @abstractmethod + def get_gate_sequence_indices(self, parity_group: IParityGroup) -> List[int]: + """ + :return: Array-like of gate-sequence indices corresponding to parity-group edge-ID's. + Returns an empty list if parity-group is not present. + """ + raise InterfaceMethodException + # endregion class GenericSurfaceCode(IGenericSurfaceCodeLayer): @@ -98,6 +107,26 @@ def __init__(self, gate_sequences: List[GateSequenceLayer], parity_group_z: List self._surface_code_layer: ISurfaceCodeLayer = surface_code_layer # endregion + # region IGenericSurfaceCodeLayer Methods + def get_gate_sequence_indices(self, parity_group: IParityGroup) -> List[int]: + """ + :return: Array-like of gate-sequence indices corresponding to parity-group edge-ID's. + Returns an empty list if parity-group is not present. + """ + # Guard clause, if parity-group is not present, return empty list + if parity_group not in self.parity_group_x + self.parity_group_z: + return [] + edge_ids: List[IEdgeID] = parity_group.edge_ids + result: List[int] = [] + for gate_sequence_index, gate_sequence in enumerate(self.gate_sequences): + contains_any_edge: bool = any([edge_id in gate_sequence.edge_ids for edge_id in edge_ids]) + if contains_any_edge: + result.append(gate_sequence_index) + continue + + return result + # endregion + # region IGateSequenceLayer Interface Methods def get_gate_sequence_at_index(self, index: int) -> GateSequenceLayer: """:return: Gate-sequence object based on round index.""" diff --git a/src/qce_circuit/library/surface_code/surface_code_connectivity.py b/src/qce_circuit/library/surface_code/surface_code_connectivity.py index f83bda5..1606784 100644 --- a/src/qce_circuit/library/surface_code/surface_code_connectivity.py +++ b/src/qce_circuit/library/surface_code/surface_code_connectivity.py @@ -321,22 +321,22 @@ def __init__(self): ], parity_group_x=[ ParityGroup( - _parity_type=StabilizerType.STABILIZER_Z, + _parity_type=StabilizerType.STABILIZER_X, _ancilla_qubit=QubitIDObj('X1'), _data_qubits=[QubitIDObj('D1'), QubitIDObj('D2')] ), ParityGroup( - _parity_type=StabilizerType.STABILIZER_Z, + _parity_type=StabilizerType.STABILIZER_X, _ancilla_qubit=QubitIDObj('X2'), _data_qubits=[QubitIDObj('D2'), QubitIDObj('D3'), QubitIDObj('D5'), QubitIDObj('D6')] ), ParityGroup( - _parity_type=StabilizerType.STABILIZER_Z, + _parity_type=StabilizerType.STABILIZER_X, _ancilla_qubit=QubitIDObj('X3'), _data_qubits=[QubitIDObj('D4'), QubitIDObj('D5'), QubitIDObj('D7'), QubitIDObj('D8')] ), ParityGroup( - _parity_type=StabilizerType.STABILIZER_Z, + _parity_type=StabilizerType.STABILIZER_X, _ancilla_qubit=QubitIDObj('X4'), _data_qubits=[QubitIDObj('D8'), QubitIDObj('D9')] ), diff --git a/src/qce_circuit/structure/circuit_modifiers.py b/src/qce_circuit/structure/circuit_modifiers.py index 2630dc5..6d946c2 100644 --- a/src/qce_circuit/structure/circuit_modifiers.py +++ b/src/qce_circuit/structure/circuit_modifiers.py @@ -183,8 +183,8 @@ def match(self, matched_operation: TMaskedTwoQubitOperation) -> bool: def construct_operation_mask(self, masked_operation: TMaskedTwoQubitOperation) -> VirtualTwoQubitVacant: """:return: Newly constructed 'mask'-operation based on masked-operation.""" return VirtualTwoQubitVacant( - control_qubit_index=masked_operation.control_qubit_index, - target_qubit_index=masked_operation.target_qubit_index, + _control_qubit_index=masked_operation.control_qubit_index, + _target_qubit_index=masked_operation.target_qubit_index, relation=masked_operation.relation_link, duration_strategy=masked_operation.duration_strategy, ) diff --git a/src/qce_circuit/structure/circuit_operations.py b/src/qce_circuit/structure/circuit_operations.py index f534f19..e70524f 100644 --- a/src/qce_circuit/structure/circuit_operations.py +++ b/src/qce_circuit/structure/circuit_operations.py @@ -1,14 +1,17 @@ # ------------------------------------------- # Module describing the declarative operations. # ------------------------------------------- +from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import List, Optional, Dict +from qce_circuit.utilities.custom_exceptions import InterfaceMethodException from qce_circuit.structure.intrf_circuit_operation import ( QubitChannel, IRelationLink, RelationLink, ChannelIdentifier, ICircuitOperation, + ITwoQubitOperation, ) from qce_circuit.structure.intrf_acquisition_operation import ( IAcquisitionOperation, @@ -594,16 +597,16 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu @dataclass(frozen=False, unsafe_hash=True) -class TwoQubitOperation(ICircuitOperation): +class TwoQubitOperation(ITwoQubitOperation): """ Minimal operation describes two-qubit implementation of ICircuitOperation. """ - control_qubit_index: int = field(init=True) - target_qubit_index: int = field(init=True) + _control_qubit_index: int = field(init=True) + _target_qubit_index: int = field(init=True) relation: IRelationLink[ICircuitOperation] = field(default_factory=RelationLink.no_relation) duration_strategy: IDurationStrategy = field(default=FixedDurationStrategy(duration=0.0)) - # region Interface Properties + # region ICircuitOperation Properties @property def channel_identifiers(self) -> List[ChannelIdentifier]: """:return: Array-like of channel identifiers to which this operation applies to.""" @@ -638,6 +641,18 @@ def duration(self) -> float: return self.duration_strategy.get_variable_duration(task=self) # endregion + # region ITwoQubitOperation Properties + @property + def control_qubit_index(self) -> int: + """:return: Index of control qubit.""" + return self._control_qubit_index + + @property + def target_qubit_index(self) -> int: + """:return: Index of target qubit.""" + return self._target_qubit_index + # endregion + # region Interface Methods def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircuitOperation]] = None) -> 'TwoQubitOperation': """ @@ -646,8 +661,8 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu :return: Copy of self with updated relation link. """ return TwoQubitOperation( - control_qubit_index=self.control_qubit_index, - target_qubit_index=self.target_qubit_index, + _control_qubit_index=self.control_qubit_index, + _target_qubit_index=self.target_qubit_index, relation=self.relation.copy(relation_transfer_lookup=relation_transfer_lookup), duration_strategy=self.duration_strategy, ) @@ -704,8 +719,8 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu :return: Copy of self with updated relation link. """ return CPhase( - control_qubit_index=self.control_qubit_index, - target_qubit_index=self.target_qubit_index, + _control_qubit_index=self.control_qubit_index, + _target_qubit_index=self.target_qubit_index, relation=self.relation.copy(relation_transfer_lookup=relation_transfer_lookup), ) # endregion @@ -736,8 +751,8 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu :return: Copy of self with updated relation link. """ return TwoQubitVirtualPhase( - control_qubit_index=self.control_qubit_index, - target_qubit_index=self.target_qubit_index, + _control_qubit_index=self.control_qubit_index, + _target_qubit_index=self.target_qubit_index, relation=self.relation.copy(relation_transfer_lookup=relation_transfer_lookup), ) # endregion @@ -864,7 +879,7 @@ class Barrier(ICircuitOperation): """ qubit_indices: List[int] = field(init=True) relation: IRelationLink[ICircuitOperation] = field(init=False, default_factory=RelationLink.no_relation) - duration_strategy: IDurationStrategy = field(init=False, default=FixedDurationStrategy(duration=0.5)) + duration_strategy: IDurationStrategy = field(init=False, default=GlobalDurationStrategy(GlobalRegistryKey.BARRIER)) # region Interface Properties @property @@ -943,6 +958,94 @@ def __hash__(self): # endregion +@dataclass(frozen=False) +class VirtualQECOperation(ICircuitOperation): + """ + Virtual QEC-block operation. + """ + qubit_indices: List[int] = field(init=True) + relation: IRelationLink[ICircuitOperation] = field(default_factory=RelationLink.no_relation) + duration_strategy: IDurationStrategy = field(default=GlobalDurationStrategy(GlobalRegistryKey.QEC_BLOCK)) + + # region Interface Properties + @property + def channel_identifiers(self) -> List[ChannelIdentifier]: + """:return: Array-like of channel identifiers to which this operation applies to.""" + return [ + ChannelIdentifier(_id=qubit_index, _channel=QubitChannel.ALL) + for qubit_index in self.qubit_indices + ] + + @property + def nr_of_repetitions(self) -> int: + """:return: Number of repetitions for this object.""" + return 1 + + @property + def relation_link(self) -> IRelationLink[ICircuitOperation]: + """:return: Description of relation to other circuit node.""" + return self.relation + + @relation_link.setter + def relation_link(self, link: IRelationLink[ICircuitOperation]): + """:sets: Description of relation to other circuit node.""" + self.relation = link + + @property + def start_time(self) -> float: + """:return: Start time [a.u.].""" + return self.relation_link.get_start_time(duration=self.duration) + + @property + def duration(self) -> float: + """:return: Duration [ns].""" + return self.duration_strategy.get_variable_duration(task=self) + # endregion + + # region Interface Methods + def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircuitOperation]] = None) -> 'VirtualQECOperation': + """ + Creates a copy from self. Excluding any relation details. + :param relation_transfer_lookup: Lookup table used to transfer relation link. + :return: Copy of self with updated relation link. + """ + return VirtualQECOperation( + qubit_indices=self.qubit_indices, + relation=self.relation.copy(relation_transfer_lookup=relation_transfer_lookup), + duration_strategy=self.duration_strategy, + ) + + def apply_modifiers_to_self(self) -> ICircuitOperation: + """ + WARNING: Applies modifiers inplace. + Applies modifiers such as repetition and state-control. + :return: Modified self. + """ + return self + + def decomposed_operations(self) -> List[ICircuitOperation]: + """ + Functions similar to a 'flatten' operation. + Mostly intended for composite-operations such that they can apply repetition and state-dependent registries. + :return: Array-like of decomposed operations. + """ + return [self] + + def apply_flatten_to_self(self) -> ICircuitOperation: + """ + WARNING: Applies a flatten modification inplace. + :return: Modified self. + """ + return self + # endregion + + # region Class Methods + def __hash__(self): + """Overwrites @dataclass behaviour. Circuit operation requires hash based on instance identity.""" + return id(self) + # endregion + + @dataclass(frozen=False, unsafe_hash=True) class VirtualVacant(SingleQubitOperation, ICircuitOperation): """ @@ -1002,8 +1105,8 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu :return: Copy of self with updated relation link. """ return VirtualTwoQubitVacant( - control_qubit_index=self.control_qubit_index, - target_qubit_index=self.target_qubit_index, + _control_qubit_index=self.control_qubit_index, + _target_qubit_index=self.target_qubit_index, relation=self.relation.copy(relation_transfer_lookup=relation_transfer_lookup), ) # endregion @@ -1127,6 +1230,8 @@ class VirtualInjectedError(ICircuitOperation): Acts as a visualization wrapper for injected errors. """ operation: SingleQubitOperation + line_style_border_overwrite: str = field(default="--") + color_background_overwrite: str = field(default="#ff9999") # region Interface Properties @property @@ -1170,7 +1275,9 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu return VirtualInjectedError( operation=self.operation.copy( relation_transfer_lookup=relation_transfer_lookup, - ) + ), + line_style_border_overwrite=self.line_style_border_overwrite, + color_background_overwrite=self.color_background_overwrite, ) def apply_modifiers_to_self(self) -> ICircuitOperation: @@ -1236,16 +1343,33 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu # endregion +class IColorOverwrite(ABC): + + # region Interface Properties + @property + @abstractmethod + def wrapped_operation(self) -> ICircuitOperation: + """:return: Wrapped operation used to pass to sub-draw factories.""" + raise InterfaceMethodException + + @property + @abstractmethod + def color_overwrite(self) -> str: + """:return: Color identifier for overwriting draw factory colors.""" + raise InterfaceMethodException + # endregion + + @dataclass(frozen=False, unsafe_hash=True) -class VirtualColorOverwrite(ICircuitOperation): +class VirtualColorOverwrite(ICircuitOperation, IColorOverwrite): """ Data class, containing single-qubit operation. Acts as a visualization wrapper for coloring visualization. """ - operation: SingleQubitOperation - color_overwrite: str = field(init=True, default="k") + operation: ICircuitOperation + _color_overwrite: str = field(init=True, default="k") - # region Interface Properties + # region ICircuitOperation Properties @property def channel_identifiers(self) -> List[ChannelIdentifier]: """:return: Array-like of channel identifiers to which this operation applies to.""" @@ -1259,12 +1383,12 @@ def nr_of_repetitions(self) -> int: @property def relation_link(self) -> IRelationLink[ICircuitOperation]: """:return: Description of relation to other circuit node.""" - return self.operation.relation + return self.operation.relation_link @relation_link.setter def relation_link(self, link: IRelationLink[ICircuitOperation]): """:sets: Description of relation to other circuit node.""" - self.operation.relation = link + self.operation.relation_link = link @property def start_time(self) -> float: @@ -1277,6 +1401,35 @@ def duration(self) -> float: return self.operation.duration # endregion + # region IColorOverwrite Properties + @property + def wrapped_operation(self) -> ICircuitOperation: + """:return: Wrapped operation used to pass to sub-draw factories.""" + return self.operation + + @property + def color_overwrite(self) -> str: + """:return: Color identifier for overwriting draw factory colors.""" + return self._color_overwrite + # endregion + + # region Class Constructor + def __new__(cls, operation: ICircuitOperation, _color_overwrite: str = "k"): + """ + Factory method to select the correct wrapper class at instantiation. + """ + # Check if the operation is a two-qubit operation. + if isinstance(operation, ITwoQubitOperation): + # If so, instantiate and return the specialized two-qubit wrapper. + return VirtualTwoQubitColorOverwrite( + operation=operation, + _color_overwrite=_color_overwrite + ) + else: + # Otherwise, proceed with the standard instantiation of this class. + return super().__new__(cls) + # endregion + # region Interface Methods def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircuitOperation]] = None) -> 'VirtualColorOverwrite': """ @@ -1287,7 +1440,112 @@ def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircu return VirtualColorOverwrite( operation=self.operation.copy( relation_transfer_lookup=relation_transfer_lookup, - ) + ), + _color_overwrite=self._color_overwrite, + ) + + def apply_modifiers_to_self(self) -> ICircuitOperation: + """ + WARNING: Applies modifiers inplace. + Applies modifiers such as repetition and state-control. + :return: Modified self. + """ + return self + + def decomposed_operations(self) -> List[ICircuitOperation]: + """ + Functions similar to a 'flatten' operation. + Mostly intended for composite-operations such that they can apply repetition and state-dependent registries. + :return: Array-like of decomposed operations. + """ + return [self] + + def apply_flatten_to_self(self) -> ICircuitOperation: + """ + WARNING: Applies a flatten modification inplace. + :return: Modified self. + """ + return self + # endregion + + +@dataclass(frozen=False, unsafe_hash=True) +class VirtualTwoQubitColorOverwrite(ITwoQubitOperation, IColorOverwrite): + """ + Virtual color overwrite operation (behaves as TwoQubitOperation). + Acts as a visualization wrapper for coloring visualization. + """ + operation: ITwoQubitOperation = field(init=True) + _color_overwrite: str = field(init=True) + + # region ICircuitOperation Properties + @property + def channel_identifiers(self) -> List[ChannelIdentifier]: + """:return: Array-like of channel identifiers to which this operation applies to.""" + return self.operation.channel_identifiers + + @property + def nr_of_repetitions(self) -> int: + """:return: Number of repetitions for this object.""" + return self.operation.nr_of_repetitions + + @property + def relation_link(self) -> IRelationLink[ICircuitOperation]: + """:return: Description of relation to other circuit node.""" + return self.operation.relation_link + + @relation_link.setter + def relation_link(self, link: IRelationLink[ICircuitOperation]): + """:sets: Description of relation to other circuit node.""" + self.operation.relation_link = link + + @property + def start_time(self) -> float: + """:return: Start time [a.u.].""" + return self.operation.start_time + + @property + def duration(self) -> float: + """:return: Duration [ns].""" + return self.operation.duration + # endregion + + # region ITwoQubitOperation Properties + @property + def control_qubit_index(self) -> int: + """:return: Index of control qubit.""" + return self.operation.control_qubit_index + + @property + def target_qubit_index(self) -> int: + """:return: Index of target qubit.""" + return self.operation.target_qubit_index + # endregion + + # region IColorOverwrite Properties + @property + def wrapped_operation(self) -> ICircuitOperation: + """:return: Wrapped operation used to pass to sub-draw factories.""" + return self.operation + + @property + def color_overwrite(self) -> str: + """:return: Color identifier for overwriting draw factory colors.""" + return self._color_overwrite + # endregion + + # region Interface Methods + def copy(self, relation_transfer_lookup: Optional[Dict[ICircuitOperation, ICircuitOperation]] = None) -> 'VirtualTwoQubitColorOverwrite': + """ + Creates a copy from self. Excluding any relation details. + :param relation_transfer_lookup: Lookup table used to transfer relation link. + :return: Copy of self with updated relation link. + """ + return VirtualTwoQubitColorOverwrite( + operation=self.operation.copy( + relation_transfer_lookup=relation_transfer_lookup, + ), + _color_overwrite=self._color_overwrite, ) def apply_modifiers_to_self(self) -> ICircuitOperation: diff --git a/src/qce_circuit/structure/intrf_circuit_operation.py b/src/qce_circuit/structure/intrf_circuit_operation.py index 05e40dc..c448be8 100644 --- a/src/qce_circuit/structure/intrf_circuit_operation.py +++ b/src/qce_circuit/structure/intrf_circuit_operation.py @@ -338,6 +338,23 @@ def __hash__(self): TCircuitOperation = TypeVar('TCircuitOperation', bound=ICircuitOperation) +class ITwoQubitOperation(ICircuitOperation, metaclass=ABCMeta): + + # region Interface Properties + @property + @abstractmethod + def control_qubit_index(self) -> int: + """:return: Index of control qubit.""" + raise InterfaceMethodException + + @property + @abstractmethod + def target_qubit_index(self) -> int: + """:return: Index of target qubit.""" + raise InterfaceMethodException + # endregion + + @dataclass(frozen=True) class MultiRelationLink(IRelationLink[TCircuitOperation], Generic[TCircuitOperation]): """ diff --git a/src/qce_circuit/structure/registry_duration.py b/src/qce_circuit/structure/registry_duration.py index c04faf4..e53b73f 100644 --- a/src/qce_circuit/structure/registry_duration.py +++ b/src/qce_circuit/structure/registry_duration.py @@ -31,6 +31,8 @@ class GlobalRegistryKey(Enum): MICROWAVE = 'default_allocated_microwave_duration' FLUX = 'default_allocated_flux_duration' RESET = 'default_allocated_reset_duration' + QEC_BLOCK = 'default_allocated_qec_duration' + BARRIER = 'default_allocated_barrier_duration' @dataclass(frozen=True) @@ -43,6 +45,8 @@ class GlobalDurationRegistry(IRegistryGetter[GlobalRegistryKey, float]): GlobalRegistryKey.MICROWAVE.value: 1.0, GlobalRegistryKey.FLUX.value: 1.0, GlobalRegistryKey.RESET.value: 2.0, + GlobalRegistryKey.QEC_BLOCK.value: 2.0, + GlobalRegistryKey.BARRIER.value: 0.5, }) # region Class Methods @@ -96,7 +100,12 @@ def temporary_override_get_registry_at(temp_registry: Dict[GlobalRegistryKey, fl original_method = GlobalDurationRegistry.get_registry_at def temp_get_registry_at(self, key: GlobalRegistryKey) -> Optional[float]: - return temp_registry.get(key, None) + extended_lookup: Dict[str, float] = GlobalDurationRegistry()._global_registry + # Update + for _key, _value in temp_registry.items(): + extended_lookup[_key.value] = _value + + return extended_lookup.get(key.value, None) try: GlobalDurationRegistry.get_registry_at = temp_get_registry_at diff --git a/src/qce_circuit/visualization/visualize_circuit/display_circuit.py b/src/qce_circuit/visualization/visualize_circuit/display_circuit.py index e34a899..d5898b9 100644 --- a/src/qce_circuit/visualization/visualize_circuit/display_circuit.py +++ b/src/qce_circuit/visualization/visualize_circuit/display_circuit.py @@ -22,6 +22,7 @@ VirtualPhase, Rphi90, CPhase, + ITwoQubitOperation, TwoQubitOperation, DispersiveMeasure, Identity, @@ -35,6 +36,8 @@ VirtualOptional, VirtualInjectedError, VirtualColorOverwrite, + VirtualTwoQubitColorOverwrite, + VirtualQECOperation, ) from qce_circuit.visualization.visualize_circuit.draw_components.annotation_components import ( HorizontalVariableIndicator, @@ -116,6 +119,7 @@ VirtualOptionalFactory, VirtualInjectedErrorFactory, VirtualColorOverwriteFactory, + VirtualQECBlockFactory, ) from qce_circuit.visualization.visualize_circuit.draw_components.factory_multi_draw_components import \ MultiTwoQubitBlockFactory @@ -154,6 +158,8 @@ class VisualCircuitDescription: composite_operations: List[ICircuitCompositeOperation] """Array of composite operations.""" channel_label_map: Dict[int, str] = field(default_factory=dict) + minimalist: bool = field(default=False) + """Minimalist drawing style, passed to factories""" # region Class Properties @property @@ -199,7 +205,7 @@ def get_transform_constructor(self) -> TransformConstructor: ) def get_operation_draw_components(self) -> List[IDrawComponent]: - minimalist: bool = False + minimalist: bool = self.minimalist individual_component_factory = DrawComponentFactoryManager( default_factory=DefaultFactory(), factory_lookup={ @@ -226,6 +232,7 @@ def get_operation_draw_components(self) -> List[IDrawComponent]: VirtualTwoQubitVacant: VirtualTwoQubitVacantFactory(), VirtualEmpty: VirtualEmptyFactory(), VirtualWait: VirtualWaitFactory(), + VirtualQECOperation: VirtualQECBlockFactory(), } ) callback_draw_manager = deepcopy(individual_component_factory) @@ -238,9 +245,10 @@ def get_operation_draw_components(self) -> List[IDrawComponent]: factory_manager: BulkDrawComponentFactoryManager = BulkDrawComponentFactoryManager( individual_component_factory=individual_component_factory, factory_lookup={ - TwoQubitOperation: MultiTwoQubitBlockFactory(factory_lookup={ + ITwoQubitOperation: MultiTwoQubitBlockFactory(factory_lookup={ CPhase: TwoQubitBlockFactory(), - VirtualTwoQubitVacant: VirtualTwoQubitVacantFactory() + VirtualTwoQubitVacant: VirtualTwoQubitVacantFactory(), + VirtualTwoQubitColorOverwrite: VirtualColorOverwriteFactory(callback_draw_manager=callback_draw_manager), }), } ) @@ -310,7 +318,7 @@ def reorder_map(original_order: Dict[T, Any], specific_order: List[T]) -> Dict[T return result -def construct_visual_description(circuit: IDeclarativeCircuit, custom_channel_order: Optional[List[int]] = None, custom_channel_map: Optional[Dict[int, str]] = None) -> VisualCircuitDescription: +def construct_visual_description(circuit: IDeclarativeCircuit, custom_channel_order: Optional[List[int]] = None, custom_channel_map: Optional[Dict[int, str]] = None, minimalist: bool = False) -> VisualCircuitDescription: """:return: Draw description based on declarative circuit interface instance.""" channel_indices: List[int] = unique_in_order([identifier.id for identifier in circuit.occupied_qubit_channels]) # Apply custom channel order @@ -346,6 +354,7 @@ def construct_visual_description(circuit: IDeclarativeCircuit, custom_channel_or channel_states=channel_states, operations=operations, composite_operations=circuit.composite_operations, + minimalist=minimalist, ) @@ -561,7 +570,7 @@ def plot_debug_schedule(**kwargs) -> IFigureAxesPair: return fig, ax -def plot_circuit(circuit: IDeclarativeCircuit, channel_order: List[int] = None, channel_map: Optional[Dict[int, str]] = None, compact_visualization: bool = True, **kwargs) -> IFigureAxesPair: +def plot_circuit(circuit: IDeclarativeCircuit, channel_order: List[int] = None, channel_map: Optional[Dict[int, str]] = None, compact_visualization: bool = True, minimalist_visualization: bool = False, **kwargs) -> IFigureAxesPair: if compact_visualization: with temporary_override_get_registry_at(VISUALIZATION_DURATION_REGISTRY): with clear_lru_cache(RelationLink.get_start_time): @@ -570,6 +579,7 @@ def plot_circuit(circuit: IDeclarativeCircuit, channel_order: List[int] = None, circuit=circuit, custom_channel_order=channel_order, custom_channel_map=channel_map, + minimalist=minimalist_visualization, ), **kwargs ) @@ -580,6 +590,7 @@ def plot_circuit(circuit: IDeclarativeCircuit, channel_order: List[int] = None, circuit=circuit, custom_channel_order=channel_order, custom_channel_map=channel_map, + minimalist=minimalist_visualization, ), **kwargs ) @@ -657,8 +668,8 @@ def plot_circuit_description(description: VisualCircuitDescription, **kwargs) -> qubit_index=0, )) sub_circuit.add(CPhase( - control_qubit_index=0, - target_qubit_index=1, + _control_qubit_index=0, + _target_qubit_index=1, )) sub_circuit.add(Rx180( qubit_index=0, diff --git a/src/qce_circuit/visualization/visualize_circuit/draw_components/factory_draw_components.py b/src/qce_circuit/visualization/visualize_circuit/draw_components/factory_draw_components.py index 1e93512..9f2a107 100644 --- a/src/qce_circuit/visualization/visualize_circuit/draw_components/factory_draw_components.py +++ b/src/qce_circuit/visualization/visualize_circuit/draw_components/factory_draw_components.py @@ -35,7 +35,8 @@ VirtualOptional, VirtualInjectedError, VirtualWait, - VirtualColorOverwrite, + IColorOverwrite, + VirtualQECOperation, ) from qce_circuit.visualization.visualize_circuit.intrf_draw_component import IDrawComponent from qce_circuit.visualization.visualize_circuit.intrf_factory_draw_components import ( @@ -64,6 +65,7 @@ BlockTwoQubitGate, BlockVerticalBarrier, BlockTwoQubitVacant, + BlockQEC, ) from qce_circuit.visualization.visualize_circuit.draw_components.annotation_components import ( HorizontalVariableIndicator, @@ -633,6 +635,24 @@ def construct(self, operation: ICircuitCompositeOperation, transform_constructor # endregion +class VirtualQECBlockFactory(IOperationDrawComponentFactory[VirtualQECOperation, IDrawComponent]): + + # region Interface Methods + def construct(self, operation: VirtualQECOperation, transform_constructor: ITransformConstructor) -> IDrawComponent: + """:return: Draw component based on operation type.""" + transforms: List[IRectTransform] = [ + transform_constructor.construct_transform( + identifier=ChannelIdentifier(_id=qubit_index, _channel=QubitChannel.ALL), + time_component=operation, + ) + for qubit_index in operation.qubit_indices + ] + return BlockQEC( + multiple_transforms=transforms, + ) + # endregion + + class VirtualOptionalFactory(IOperationDrawComponentFactory[VirtualOptional, IDrawComponent]): """ Behaviour class, implementing construction of draw component with additional requirements. @@ -668,7 +688,10 @@ def __init__(self, callback_draw_manager: IOperationDrawComponentFactoryManager) # region Interface Methods def construct(self, operation: VirtualInjectedError, transform_constructor: ITransformConstructor) -> IDrawComponent: """:return: Draw component based on operation type.""" - with StyleManager.temporary_override(**dict(line_style_border='--', color_background="#ff9999")): + with StyleManager.temporary_override(**dict( + line_style_border=operation.line_style_border_overwrite, + color_background=operation.color_background_overwrite, + )): draw_component: IDrawComponent = self._factory_manager.construct( operation=operation.operation, transform_constructor=transform_constructor, @@ -677,7 +700,7 @@ def construct(self, operation: VirtualInjectedError, transform_constructor: ITra # endregion -class VirtualColorOverwriteFactory(IOperationDrawComponentFactory[VirtualColorOverwrite, IDrawComponent]): +class VirtualColorOverwriteFactory(IOperationDrawComponentFactory[IColorOverwrite, IDrawComponent]): """ Behaviour class, implementing construction of draw component with additional requirements. """ @@ -688,15 +711,16 @@ def __init__(self, callback_draw_manager: IOperationDrawComponentFactoryManager) # endregion # region Interface Methods - def construct(self, operation: VirtualColorOverwrite, transform_constructor: ITransformConstructor) -> IDrawComponent: + def construct(self, operation: IColorOverwrite, transform_constructor: ITransformConstructor) -> IDrawComponent: """:return: Draw component based on operation type.""" with StyleManager.temporary_override(**dict( color_text=operation.color_overwrite, color_icon=operation.color_overwrite, color_outline=operation.color_overwrite, + color_outline_dim=operation.color_overwrite, )): draw_component: IDrawComponent = self._factory_manager.construct( - operation=operation.operation, + operation=operation.wrapped_operation, transform_constructor=transform_constructor, ) return draw_component diff --git a/src/qce_circuit/visualization/visualize_circuit/draw_components/multi_pivot_components.py b/src/qce_circuit/visualization/visualize_circuit/draw_components/multi_pivot_components.py index 36f76f3..1be5dfa 100644 --- a/src/qce_circuit/visualization/visualize_circuit/draw_components/multi_pivot_components.py +++ b/src/qce_circuit/visualization/visualize_circuit/draw_components/multi_pivot_components.py @@ -214,9 +214,11 @@ def draw(self, axes: plt.Axes) -> plt.Axes: # TODO: Add logic based on attributes DotComponent( base_transform=self.main_transform_block, + style_settings=self.style_settings, ).draw(axes=axes) DotComponent( base_transform=self.second_transform_block, + style_settings=self.style_settings, ).draw(axes=axes) # CrossComponent( # base_transform=self.second_transform_block, @@ -325,3 +327,57 @@ def draw(self, axes: plt.Axes) -> plt.Axes: ) return axes # endregion + + +@dataclass(frozen=True) +class BlockQEC(IRectTransformComponent, IDrawComponent): + """ + Data class, containing information to draw a vertical barrier block + that uses multiple pivots to comply with vertical alignment. + """ + multiple_transforms: List[IRectTransform] + style_settings: OperationStyleSettings = field(default_factory=lambda: StyleManager.read_config().operation_style) + + # region Interface Properties + @property + def rectilinear_transform(self) -> IRectTransform: + """:return: 'Hard' rectilinear transform boundary. Should be treated as 'personal zone'.""" + return ITransformConstructor.combine_transforms(self.rectilinear_transforms) + # endregion + + # region Class Properties + @property + def rectilinear_transforms(self) -> List[IRectTransform]: + return self.multiple_transforms + + @property + def text_center(self) -> Vec2D: + return self.rectilinear_transform.center_pivot + # endregion + + # region Interface Methods + def draw(self, axes: plt.Axes) -> plt.Axes: + """Method used for drawing component on Axes.""" + + rectangle = patches.Rectangle( + xy=self.rectilinear_transform.origin_pivot.to_tuple(), + width=self.rectilinear_transform.width, + height=self.rectilinear_transform.height, + linewidth=self.style_settings.border_width, + linestyle=self.style_settings.border_line_style, + edgecolor=self.style_settings.border_color, + facecolor=self.style_settings.background_color, + zorder=-1, + ) + axes.add_patch(rectangle) + axes.text( + x=self.text_center.x, + y=self.text_center.y, + s="QEC", + fontsize=self.style_settings.font_size, + color=self.style_settings.text_color, + ha='center', + va='center', + ) + return axes + # endregion diff --git a/src/qce_circuit/visualization/visualize_circuit/draw_components/operation_components.py b/src/qce_circuit/visualization/visualize_circuit/draw_components/operation_components.py index 0cfae89..98019fb 100644 --- a/src/qce_circuit/visualization/visualize_circuit/draw_components/operation_components.py +++ b/src/qce_circuit/visualization/visualize_circuit/draw_components/operation_components.py @@ -21,6 +21,7 @@ from qce_circuit.visualization.visualize_circuit.style_manager import ( StyleManager, OperationStyleSettings, + IconStyleSettings, ChannelStyleSettings, ) @@ -226,6 +227,7 @@ class BlockMeasure(IRectTransformComponent, IDrawComponent): height: float alignment: TransformAlignment = field(default=TransformAlignment.MID_LEFT) style_settings: OperationStyleSettings = field(default_factory=lambda: StyleManager.read_config().operation_style) + icon_style_settings: IconStyleSettings = field(default_factory=lambda: StyleManager.read_config().icon_style) _base_block: RectangleBlock = field(init=False) # region Interface Properties @@ -246,6 +248,7 @@ def icon(self) -> IconMeasure: return IconMeasure( center=icon_center, radius=icon_radius, + style_settings=self.icon_style_settings ) # endregion diff --git a/src/qce_circuit/visualization/visualize_circuit/intrf_factory_draw_components.py b/src/qce_circuit/visualization/visualize_circuit/intrf_factory_draw_components.py index 359bf5b..4ff4327 100644 --- a/src/qce_circuit/visualization/visualize_circuit/intrf_factory_draw_components.py +++ b/src/qce_circuit/visualization/visualize_circuit/intrf_factory_draw_components.py @@ -13,7 +13,10 @@ IDurationComponent, ChannelIdentifier, ) -from qce_circuit.structure.circuit_operations import TwoQubitOperation +from qce_circuit.structure.circuit_operations import ( + TwoQubitOperation, + ITwoQubitOperation, +) from qce_circuit.utilities.geometric_definitions import ( IRectTransform, TransformAlignment, @@ -179,8 +182,8 @@ def construct(self, operations: List[ICircuitOperation], transform_constructor: for operation in operations: operation_type = type(operation) # Work around, grouping two-qubit operations - if isinstance(operation, TwoQubitOperation): - operation_type = TwoQubitOperation + if isinstance(operation, ITwoQubitOperation): + operation_type = ITwoQubitOperation if operation_type not in operation_lookup: operation_lookup[operation_type] = [operation] diff --git a/src/qce_circuit/visualization/visualize_layout/display_connectivity.py b/src/qce_circuit/visualization/visualize_layout/display_connectivity.py index 29e4032..8c2ebec 100644 --- a/src/qce_circuit/visualization/visualize_layout/display_connectivity.py +++ b/src/qce_circuit/visualization/visualize_layout/display_connectivity.py @@ -5,6 +5,7 @@ from collections.abc import Iterable from typing import Dict, List, Union import numpy as np +import math from qce_circuit.connectivity.intrf_channel_identifier import IQubitID, QubitIDObj from qce_circuit.connectivity.intrf_connectivity_surface_code import ISurfaceCodeLayer, IParityGroup from qce_circuit.connectivity.connectivity_surface_code import Surface17Layer @@ -66,6 +67,7 @@ class VisualConnectivityDescription: layout_spacing: float = field(default=1.0) pivot: Vec2D = field(default=Vec2D(0, 0)) rotation: float = field(default=-45) + include_element_labels: bool = field(default=True) # region Class Methods def get_plaquette_components(self) -> List[IDrawComponent]: @@ -173,11 +175,12 @@ def get_element_components(self) -> List[IDrawComponent]: pivot=self.identifier_to_pivot(qubit_id) + self.pivot, alignment=TransformAlignment.MID_CENTER, )) - result.append(TextComponent( - pivot=self.identifier_to_pivot(qubit_id) + self.pivot, - text=qubit_id.id, - alignment=TransformAlignment.MID_CENTER, - )) + if self.include_element_labels: + result.append(TextComponent( + pivot=self.identifier_to_pivot(qubit_id) + self.pivot, + text=qubit_id.id, + alignment=TransformAlignment.MID_CENTER, + )) return result def get_line_components(self) -> List[IDrawComponent]: @@ -200,15 +203,15 @@ def get_line_components(self) -> List[IDrawComponent]: def get_operation_components(self) -> List[IDrawComponent]: park_components: List[IDrawComponent] = [ ParkingComponent( - pivot=self.identifier_to_pivot(identifier=operation.identifier), + pivot=self.identifier_to_pivot(identifier=operation.identifier) + self.pivot, alignment=TransformAlignment.MID_CENTER, ) for operation in self.gate_sequence.park_operations ] gate_components: List[IDrawComponent] = [ GateOperationComponent( - pivot0=self.identifier_to_pivot(identifier=operation.identifier.qubit_ids[0]), - pivot1=self.identifier_to_pivot(identifier=operation.identifier.qubit_ids[1]), + pivot0=self.identifier_to_pivot(identifier=operation.identifier.qubit_ids[0]) + self.pivot, + pivot1=self.identifier_to_pivot(identifier=operation.identifier.qubit_ids[1]) + self.pivot, alignment=TransformAlignment.MID_CENTER, ) for operation in self.gate_sequence.gate_operations @@ -268,21 +271,22 @@ def identifier_to_rotation(self, identifier: Union[IQubitID, IParityGroup]) -> f ) mean_center: bool = all(np.isclose(mean_relative_coordinates.to_vector(), Vec2D(0.0, 0.0).to_vector())) + absolute_tolerance: float = 1e-9 if mean_center: # Weight-2 diagonal line = Line2D(start=relative_coordinates[0], end=relative_coordinates[1]) slope = (line.end.y - line.start.y) / (line.end.x - line.start.x) - if slope == +1.0: + if math.isclose(slope, +1.0, abs_tol=absolute_tolerance): pass - elif slope == -1.0: + elif math.isclose(slope, -1.0, abs_tol=absolute_tolerance): rotation_offset += 90 else: # Weight-2 triangle - if mean_relative_coordinates.x == 0.0 and mean_relative_coordinates.y > 0.0: + if math.isclose(mean_relative_coordinates.x, 0.0, abs_tol=absolute_tolerance) and mean_relative_coordinates.y > 0.0: rotation_offset += 90 - elif mean_relative_coordinates.x == 0.0 and mean_relative_coordinates.y < 0.0: + elif math.isclose(mean_relative_coordinates.x, 0.0, abs_tol=absolute_tolerance) and mean_relative_coordinates.y < 0.0: rotation_offset += 270 - elif mean_relative_coordinates.x > 0.0 and mean_relative_coordinates.y == 0.0: + elif mean_relative_coordinates.x > 0.0 and math.isclose(mean_relative_coordinates.y, 0.0, abs_tol=absolute_tolerance): rotation_offset += 0 - elif mean_relative_coordinates.x < 0.0 and mean_relative_coordinates.y == 0.0: + elif mean_relative_coordinates.x < 0.0 and math.isclose(mean_relative_coordinates.y, 0.0, abs_tol=absolute_tolerance): rotation_offset += 180 if identifier.ancilla_id in self.connectivity.ancilla_qubit_ids: @@ -390,11 +394,12 @@ def get_element_components(self) -> List[IDrawComponent]: zorder=style_setting.zorder_element, ), )) - result.append(TextComponent( - pivot=self.identifier_to_pivot(qubit_id) + self.pivot, - text=qubit_id.id, - alignment=TransformAlignment.MID_CENTER, - )) + if self.include_element_labels: + result.append(TextComponent( + pivot=self.identifier_to_pivot(qubit_id) + self.pivot, + text=qubit_id.id, + alignment=TransformAlignment.MID_CENTER, + )) return result # endregion @@ -439,7 +444,7 @@ def plot_gate_sequences(description: IGenericSurfaceCodeLayer, **kwargs) -> IFig return fig, axes[0] -def plot_stabilizer_specific_gate_sequences(description: IGenericSurfaceCodeLayer, **kwargs) -> IFigureAxesPair: +def plot_stabilizer_specific_gate_sequences(description: IGenericSurfaceCodeLayer, include_element_labels: bool = True, **kwargs) -> IFigureAxesPair: """ Constructs a similar gate sequence plot as 'plot_gate_sequences'. However, the gate-sequence info is taken from description parameter @@ -447,6 +452,7 @@ def plot_stabilizer_specific_gate_sequences(description: IGenericSurfaceCodeLaye Allowing for extra flexibility. :param description: Generic surface code layer definition including parity-groups and gate sequence. :param kwargs: Keyword arguments passed to figure constructor. + :param include_element_labels: Boolean to enable or disable element label text. :return: Figure and Axes pair. """ sequence_count: int = description.gate_sequence_count @@ -459,7 +465,8 @@ def plot_stabilizer_specific_gate_sequences(description: IGenericSurfaceCodeLaye descriptor: AllGreyVisualConnectivityDescription = AllGreyVisualConnectivityDescription( connectivity=Surface17Layer(), gate_sequence=description.get_gate_sequence_at_index(i), - layout_spacing=1.0 + layout_spacing=1.0, + include_element_labels=include_element_labels, ) kwargs[SubplotKeywordEnum.HOST_AXES.value] = (fig, ax) fig, ax = plot_layout_description(descriptor, **kwargs) @@ -467,7 +474,8 @@ def plot_stabilizer_specific_gate_sequences(description: IGenericSurfaceCodeLaye descriptor: StabilizerGroupVisualConnectivityDescription = StabilizerGroupVisualConnectivityDescription( connectivity=description, gate_sequence=description.get_gate_sequence_at_index(i), - layout_spacing=1.0 + layout_spacing=1.0, + include_element_labels=include_element_labels, ) kwargs[SubplotKeywordEnum.HOST_AXES.value] = (fig, ax) plot_layout_description(descriptor, **kwargs) diff --git a/tests/language/test_declarative_circuit.py b/tests/language/test_declarative_circuit.py index a45491b..60d61ec 100644 --- a/tests/language/test_declarative_circuit.py +++ b/tests/language/test_declarative_circuit.py @@ -41,8 +41,8 @@ def test_circuit_example_0(self): qubit_index=2, )) circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=2, + _control_qubit_index=8, + _target_qubit_index=2, )) circuit.add(VirtualPhase( qubit_index=2, @@ -85,8 +85,8 @@ def test_circuit_example_1(self): qubit_index=8, )) circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=2, + _control_qubit_index=8, + _target_qubit_index=2, )) # Park circuit.add(VirtualPhase( @@ -97,8 +97,8 @@ def test_circuit_example_1(self): )) circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=0, + _control_qubit_index=8, + _target_qubit_index=0, )) # Park circuit.add(VirtualPhase( @@ -149,8 +149,8 @@ def test_circuit_example_2(self): qubit_index=0, )) circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=2, + _control_qubit_index=8, + _target_qubit_index=2, )) # Park circuit.add(VirtualPhase( @@ -161,8 +161,8 @@ def test_circuit_example_2(self): )) circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=0, + _control_qubit_index=8, + _target_qubit_index=0, )) # Park circuit.add(VirtualPhase( @@ -215,8 +215,8 @@ def test_circuit_example_3(self): qubit_index=0, )) sub_circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=2, + _control_qubit_index=8, + _target_qubit_index=2, )) # Park sub_circuit.add(VirtualPhase( @@ -227,8 +227,8 @@ def test_circuit_example_3(self): )) sub_circuit.add(CPhase( - control_qubit_index=8, - target_qubit_index=0, + _control_qubit_index=8, + _target_qubit_index=0, )) # Park sub_circuit.add(VirtualPhase( @@ -324,12 +324,12 @@ def test_circuit_example_4(self): qubit_index=qubit_ancilla_index, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla_index, - target_qubit_index=qubit_data1_index, + _control_qubit_index=qubit_ancilla_index, + _target_qubit_index=qubit_data1_index, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla_index, - target_qubit_index=qubit_data2_index, + _control_qubit_index=qubit_ancilla_index, + _target_qubit_index=qubit_data2_index, )) relation: RelationLink = RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) individual_parity_circuit.add(Rym90( @@ -405,25 +405,25 @@ def test_circuit_example_5(self): qubit_index=qubit_ancilla1_index, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla1_index, - target_qubit_index=qubit_data2_index, + _control_qubit_index=qubit_ancilla1_index, + _target_qubit_index=qubit_data2_index, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla1_index, - target_qubit_index=qubit_data1_index, + _control_qubit_index=qubit_ancilla1_index, + _target_qubit_index=qubit_data1_index, )) individual_parity_circuit.add(Rym90( qubit_index=qubit_ancilla1_index, )) relation: RelationLink = RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla2_index, - target_qubit_index=qubit_data3_index, + _control_qubit_index=qubit_ancilla2_index, + _target_qubit_index=qubit_data3_index, relation=relation, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla2_index, - target_qubit_index=qubit_data2_index, + _control_qubit_index=qubit_ancilla2_index, + _target_qubit_index=qubit_data2_index, )) repeated_parity_circuit: DeclarativeCircuit = DeclarativeCircuit( @@ -746,22 +746,22 @@ def test_circuit_example_6(self): relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.JOINED_START) )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla1_index, - target_qubit_index=qubit_data2_index, + _control_qubit_index=qubit_ancilla1_index, + _target_qubit_index=qubit_data2_index, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla3_index, - target_qubit_index=qubit_data4_index, + _control_qubit_index=qubit_ancilla3_index, + _target_qubit_index=qubit_data4_index, relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla1_index, - target_qubit_index=qubit_data1_index, + _control_qubit_index=qubit_ancilla1_index, + _target_qubit_index=qubit_data1_index, relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla3_index, - target_qubit_index=qubit_data5_index, + _control_qubit_index=qubit_ancilla3_index, + _target_qubit_index=qubit_data5_index, relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) )) individual_parity_circuit.add(Rym90( @@ -782,22 +782,22 @@ def test_circuit_example_6(self): relation=relation )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla2_index, - target_qubit_index=qubit_data3_index, + _control_qubit_index=qubit_ancilla2_index, + _target_qubit_index=qubit_data3_index, )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla4_index, - target_qubit_index=qubit_data1_index, + _control_qubit_index=qubit_ancilla4_index, + _target_qubit_index=qubit_data1_index, relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla2_index, - target_qubit_index=qubit_data2_index, + _control_qubit_index=qubit_ancilla2_index, + _target_qubit_index=qubit_data2_index, relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) )) individual_parity_circuit.add(CPhase( - control_qubit_index=qubit_ancilla4_index, - target_qubit_index=qubit_data4_index, + _control_qubit_index=qubit_ancilla4_index, + _target_qubit_index=qubit_data4_index, relation=RelationLink(individual_parity_circuit.get_last_entry(), RelationType.FOLLOWED_BY) )) individual_parity_circuit.add(Rym90(