From 8c74a49dcdd3ea01f5fa9c1cf59a4f6b2d4bb39d Mon Sep 17 00:00:00 2001 From: aeddins-ibm <60495383+aeddins-ibm@users.noreply.github.com> Date: Thu, 15 Aug 2024 03:42:41 -0400 Subject: [PATCH 01/85] Fix setter so that `SparsePauliOp.paulis.phase` stays zero (#12884) * absorb `phase` into `coeffs` in `paulis()` setter * do not mutate input array * add test that paulis setter absorbs phase * lint * If input paulis have phase, mutate and warn * add release note * release-note formatting * add test with `simplify()` * remove phase-warning from paulis setter * lint * remove unused import * update reno --- .../operators/symplectic/sparse_pauli_op.py | 2 ++ ...rsepauliop-phase-bug-2b24f4b775ca564f.yaml | 8 ++++++++ .../symplectic/test_sparse_pauli_op.py | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 releasenotes/notes/fix-sparsepauliop-phase-bug-2b24f4b775ca564f.yaml diff --git a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py index 10d76f8719af..4621019a9d81 100644 --- a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +++ b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py @@ -256,6 +256,8 @@ def paulis(self, value): raise ValueError( f"incorrect number of operators: expected {len(self.paulis)}, got {len(value)}" ) + self.coeffs *= (-1j) ** value.phase + value.phase = 0 self._pauli_list = value @property diff --git a/releasenotes/notes/fix-sparsepauliop-phase-bug-2b24f4b775ca564f.yaml b/releasenotes/notes/fix-sparsepauliop-phase-bug-2b24f4b775ca564f.yaml new file mode 100644 index 000000000000..ff1cf96dd711 --- /dev/null +++ b/releasenotes/notes/fix-sparsepauliop-phase-bug-2b24f4b775ca564f.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixed a bug when :attr:`.SparsePauliOp.paulis` is set to be a :class:`.PauliList` with nonzero + phase, where subsequent calls to several :class:`.SparsePauliOp` methods would produce + incorrect results. Now when :attr:`.SparsePauliOp.paulis` is set to a :class:`.PauliList` with + nonzero phase, the phase is absorbed into :attr:`.SparsePauliOp.coeffs`, and the phase of the + input :class:`.PauliList` is set to zero. diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py index 4964b0c6a609..dedd84279a8d 100644 --- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py +++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py @@ -1097,6 +1097,25 @@ def test_paulis_setter_rejects_bad_inputs(self): with self.assertRaisesRegex(ValueError, "incorrect number of operators"): op.paulis = PauliList([Pauli("XY"), Pauli("ZX"), Pauli("YZ")]) + def test_paulis_setter_absorbs_phase(self): + """Test that the setter for `paulis` absorbs `paulis.phase` to `self.coeffs`.""" + coeffs_init = np.array([1, 1j]) + op = SparsePauliOp(["XY", "ZX"], coeffs=coeffs_init) + paulis_new = PauliList(["-1jXY", "1jZX"]) + op.paulis = paulis_new + # Paulis attribute should have no phase: + self.assertEqual(op.paulis, PauliList(["XY", "ZX"])) + # Coeffs attribute should now include that phase: + self.assertTrue(np.allclose(op.coeffs, coeffs_init * np.array([-1j, 1j]))) + # The phase of the input array is now zero: + self.assertTrue(np.allclose(paulis_new.phase, np.array([0, 0]))) + + def test_paulis_setter_absorbs_phase_2(self): + """Test that `paulis` setter followed by `simplify()` handle phase OK.""" + spo = SparsePauliOp(["X", "X"]) + spo.paulis = ["X", "-X"] + self.assertEqual(spo.simplify(), SparsePauliOp(["I"], coeffs=[0.0 + 0.0j])) + def test_apply_layout_with_transpile(self): """Test the apply_layout method with a transpiler layout.""" psi = EfficientSU2(4, reps=4, entanglement="circular") From 713ab38cccb7e55a40a87372a2590a5a4430fa8f Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 15 Aug 2024 19:34:50 +0200 Subject: [PATCH 02/85] Internally importing `qiskit.providers.backend.Backend` should not raise `DeprecationWarning` (#12906) * better module deprecation * _pulse_library * __getattr__ * copy qiskit.qobj.PulseQobjInstruction and qiskit.qobj.PulseLibraryItem for internal generic_backend_v2 usage * lint * Aer models * skip * more generic catch * specific imports --- qiskit/compiler/transpiler.py | 2 +- .../basic_provider/basic_simulator.py | 2 +- .../fake_provider/fake_openpulse_2q.py | 6 +- .../fake_provider/fake_openpulse_3q.py | 5 +- .../fake_provider/fake_pulse_backend.py | 3 +- .../fake_provider/fake_qasm_backend.py | 3 +- .../fake_provider/generic_backend_v2.py | 452 +++++++++++++++++- qiskit/providers/models/__init__.py | 68 ++- .../passes/synthesis/unitary_synthesis.py | 2 +- test/benchmarks/pulse/load_pulse_defaults.py | 2 +- test/python/providers/faulty_backends.py | 2 +- test/python/providers/test_backendstatus.py | 2 +- test/python/providers/test_fake_backends.py | 2 +- .../python/transpiler/test_pulse_gate_pass.py | 2 +- test/utils/base.py | 2 +- 15 files changed, 499 insertions(+), 56 deletions(-) diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index 929089c4ac41..5e2dcf8a1560 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -23,7 +23,7 @@ from qiskit.dagcircuit import DAGCircuit from qiskit.providers.backend import Backend from qiskit.providers.backend_compat import BackendV2Converter -from qiskit.providers.models import BackendProperties +from qiskit.providers.models.backendproperties import BackendProperties from qiskit.pulse import Schedule, InstructionScheduleMap from qiskit.transpiler import Layout, CouplingMap, PropertySet from qiskit.transpiler.basepasses import BasePass diff --git a/qiskit/providers/basic_provider/basic_simulator.py b/qiskit/providers/basic_provider/basic_simulator.py index 32666c57f184..fd535d9f7278 100644 --- a/qiskit/providers/basic_provider/basic_simulator.py +++ b/qiskit/providers/basic_provider/basic_simulator.py @@ -43,7 +43,7 @@ from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping, GlobalPhaseGate from qiskit.providers import Provider from qiskit.providers.backend import BackendV2 -from qiskit.providers.models import BackendConfiguration +from qiskit.providers.models.backendconfiguration import BackendConfiguration from qiskit.providers.options import Options from qiskit.qobj import QasmQobj, QasmQobjConfig, QasmQobjExperiment from qiskit.result import Result diff --git a/qiskit/providers/fake_provider/fake_openpulse_2q.py b/qiskit/providers/fake_provider/fake_openpulse_2q.py index c76f4e048828..036c0bc6c1b7 100644 --- a/qiskit/providers/fake_provider/fake_openpulse_2q.py +++ b/qiskit/providers/fake_provider/fake_openpulse_2q.py @@ -16,14 +16,14 @@ import datetime import warnings -from qiskit.providers.models import ( +from qiskit.providers.models.backendconfiguration import ( GateConfig, PulseBackendConfiguration, - PulseDefaults, - Command, UchannelLO, ) + from qiskit.providers.models.backendproperties import Nduv, Gate, BackendProperties +from qiskit.providers.models.pulsedefaults import PulseDefaults, Command from qiskit.qobj import PulseQobjInstruction from .fake_backend import FakeBackend diff --git a/qiskit/providers/fake_provider/fake_openpulse_3q.py b/qiskit/providers/fake_provider/fake_openpulse_3q.py index 36b66847dad4..424cad006ed8 100644 --- a/qiskit/providers/fake_provider/fake_openpulse_3q.py +++ b/qiskit/providers/fake_provider/fake_openpulse_3q.py @@ -15,13 +15,12 @@ """ import warnings -from qiskit.providers.models import ( +from qiskit.providers.models.backendconfiguration import ( GateConfig, PulseBackendConfiguration, - PulseDefaults, - Command, UchannelLO, ) +from qiskit.providers.models.pulsedefaults import PulseDefaults, Command from qiskit.qobj import PulseQobjInstruction from .fake_backend import FakeBackend diff --git a/qiskit/providers/fake_provider/fake_pulse_backend.py b/qiskit/providers/fake_provider/fake_pulse_backend.py index fdb02f7d4350..bf772d339bc7 100644 --- a/qiskit/providers/fake_provider/fake_pulse_backend.py +++ b/qiskit/providers/fake_provider/fake_pulse_backend.py @@ -15,7 +15,8 @@ """ from qiskit.exceptions import QiskitError -from qiskit.providers.models import PulseBackendConfiguration, PulseDefaults +from qiskit.providers.models.backendconfiguration import PulseBackendConfiguration +from qiskit.providers.models.pulsedefaults import PulseDefaults from .fake_qasm_backend import FakeQasmBackend from .utils.json_decoder import decode_pulse_defaults diff --git a/qiskit/providers/fake_provider/fake_qasm_backend.py b/qiskit/providers/fake_provider/fake_qasm_backend.py index 7ad7222f7907..a570ac401601 100644 --- a/qiskit/providers/fake_provider/fake_qasm_backend.py +++ b/qiskit/providers/fake_provider/fake_qasm_backend.py @@ -19,7 +19,8 @@ import warnings from qiskit.exceptions import QiskitError -from qiskit.providers.models import BackendProperties, QasmBackendConfiguration +from qiskit.providers.models.backendproperties import BackendProperties +from qiskit.providers.models.backendconfiguration import QasmBackendConfiguration from .utils.json_decoder import ( decode_backend_configuration, diff --git a/qiskit/providers/fake_provider/generic_backend_v2.py b/qiskit/providers/fake_provider/generic_backend_v2.py index 6374a0b0b60a..770c8762152e 100644 --- a/qiskit/providers/fake_provider/generic_backend_v2.py +++ b/qiskit/providers/fake_provider/generic_backend_v2.py @@ -16,6 +16,7 @@ import warnings from collections.abc import Iterable +from typing import List, Dict, Any, Union import numpy as np from qiskit import pulse @@ -35,12 +36,12 @@ from qiskit.providers import Options from qiskit.providers.basic_provider import BasicSimulator from qiskit.providers.backend import BackendV2 -from qiskit.providers.models import ( - PulseDefaults, - Command, -) -from qiskit.qobj import PulseQobjInstruction, PulseLibraryItem from qiskit.utils import optionals as _optionals +from qiskit.providers.models.pulsedefaults import Command +from qiskit.qobj.converters.pulse_instruction import QobjToInstructionConverter +from qiskit.pulse.calibration_entries import PulseQobjDef +from qiskit.providers.models.pulsedefaults import MeasurementKernel, Discriminator +from qiskit.qobj.pulse_qobj import QobjMeasurementOption # Noise default values/ranges for duration and error of supported # instructions. There are two possible formats: @@ -74,17 +75,432 @@ "frequency": (5e9, 5.5e9), } -# The number of samples determines the pulse durations of the corresponding -# instructions. This default defines pulses with durations in multiples of -# 16 dt for consistency with the pulse granularity of real IBM devices, but -# keeps the number smaller than what would be realistic for -# manageability. If needed, more realistic durations could be added in the -# future (order of 160dt for 1q gates, 1760dt for 2q gates and measure). -_PULSE_LIBRARY = [ - PulseLibraryItem(name="pulse_1", samples=np.linspace(0, 1.0, 16, dtype=np.complex128)), # 16dt - PulseLibraryItem(name="pulse_2", samples=np.linspace(0, 1.0, 32, dtype=np.complex128)), # 32dt - PulseLibraryItem(name="pulse_3", samples=np.linspace(0, 1.0, 64, dtype=np.complex128)), # 64dt -] + +class PulseDefaults: + """Internal - Description of default settings for Pulse systems. These are instructions + or settings that + may be good starting points for the Pulse user. The user may modify these defaults for custom + scheduling. + """ + + # Copy from the deprecated from qiskit.providers.models.pulsedefaults.PulseDefaults + + _data = {} + + def __init__( + self, + qubit_freq_est: List[float], + meas_freq_est: List[float], + buffer: int, + pulse_library: List[PulseLibraryItem], + cmd_def: List[Command], + meas_kernel: MeasurementKernel = None, + discriminator: Discriminator = None, + **kwargs: Dict[str, Any], + ): + """ + Validate and reformat transport layer inputs to initialize. + Args: + qubit_freq_est: Estimated qubit frequencies in GHz. + meas_freq_est: Estimated measurement cavity frequencies in GHz. + buffer: Default buffer time (in units of dt) between pulses. + pulse_library: Pulse name and sample definitions. + cmd_def: Operation name and definition in terms of Commands. + meas_kernel: The measurement kernels + discriminator: The discriminators + **kwargs: Other attributes for the super class. + """ + self._data = {} + self.buffer = buffer + self.qubit_freq_est = [freq * 1e9 for freq in qubit_freq_est] + """Qubit frequencies in Hertz.""" + self.meas_freq_est = [freq * 1e9 for freq in meas_freq_est] + """Measurement frequencies in Hertz.""" + self.pulse_library = pulse_library + self.cmd_def = cmd_def + self.instruction_schedule_map = InstructionScheduleMap() + self.converter = QobjToInstructionConverter(pulse_library) + + for inst in cmd_def: + entry = PulseQobjDef(converter=self.converter, name=inst.name) + entry.define(inst.sequence, user_provided=False) + self.instruction_schedule_map._add( + instruction_name=inst.name, + qubits=tuple(inst.qubits), + entry=entry, + ) + + if meas_kernel is not None: + self.meas_kernel = meas_kernel + if discriminator is not None: + self.discriminator = discriminator + + self._data.update(kwargs) + + def __getattr__(self, name): + try: + return self._data[name] + except KeyError as ex: + raise AttributeError(f"Attribute {name} is not defined") from ex + + def to_dict(self): + """Return a dictionary format representation of the PulseDefaults. + Returns: + dict: The dictionary form of the PulseDefaults. + """ + out_dict = { + "qubit_freq_est": self.qubit_freq_est, + "meas_freq_est": self.qubit_freq_est, + "buffer": self.buffer, + "pulse_library": [x.to_dict() for x in self.pulse_library], + "cmd_def": [x.to_dict() for x in self.cmd_def], + } + if hasattr(self, "meas_kernel"): + out_dict["meas_kernel"] = self.meas_kernel.to_dict() + if hasattr(self, "discriminator"): + out_dict["discriminator"] = self.discriminator.to_dict() + for key, value in self.__dict__.items(): + if key not in [ + "qubit_freq_est", + "meas_freq_est", + "buffer", + "pulse_library", + "cmd_def", + "meas_kernel", + "discriminator", + "converter", + "instruction_schedule_map", + ]: + out_dict[key] = value + out_dict.update(self._data) + + out_dict["qubit_freq_est"] = [freq * 1e-9 for freq in self.qubit_freq_est] + out_dict["meas_freq_est"] = [freq * 1e-9 for freq in self.meas_freq_est] + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new PulseDefaults object from a dictionary. + + Args: + data (dict): A dictionary representing the PulseDefaults + to create. It will be in the same format as output by + :meth:`to_dict`. + Returns: + PulseDefaults: The PulseDefaults from the input dictionary. + """ + schema = { + "pulse_library": PulseLibraryItem, # The class PulseLibraryItem is deprecated + "cmd_def": Command, + "meas_kernel": MeasurementKernel, + "discriminator": Discriminator, + } + + # Pulse defaults data is nested dictionary. + # To avoid deepcopy and avoid mutating the source object, create new dict here. + in_data = {} + for key, value in data.items(): + if key in schema: + with warnings.catch_warnings(): + # The class PulseLibraryItem is deprecated + warnings.filterwarnings("ignore", category=DeprecationWarning, module="qiskit") + if isinstance(value, list): + in_data[key] = list(map(schema[key].from_dict, value)) + else: + in_data[key] = schema[key].from_dict(value) + else: + in_data[key] = value + + return cls(**in_data) + + def __str__(self): + qubit_freqs = [freq / 1e9 for freq in self.qubit_freq_est] + meas_freqs = [freq / 1e9 for freq in self.meas_freq_est] + qfreq = f"Qubit Frequencies [GHz]\n{qubit_freqs}" + mfreq = f"Measurement Frequencies [GHz]\n{meas_freqs} " + return f"<{self.__class__.__name__}({str(self.instruction_schedule_map)}{qfreq}\n{mfreq})>" + + +def _to_complex(value: Union[List[float], complex]) -> complex: + """Convert the input value to type ``complex``. + Args: + value: Value to be converted. + Returns: + Input value in ``complex``. + Raises: + TypeError: If the input value is not in the expected format. + """ + if isinstance(value, list) and len(value) == 2: + return complex(value[0], value[1]) + elif isinstance(value, complex): + return value + + raise TypeError(f"{value} is not in a valid complex number format.") + + +class PulseLibraryItem: + """INTERNAL - An item in a pulse library.""" + + # Copy from the deprecated from qiskit.qobj.PulseLibraryItem + def __init__(self, name, samples): + """Instantiate a pulse library item. + + Args: + name (str): A name for the pulse. + samples (list[complex]): A list of complex values defining pulse + shape. + """ + self.name = name + if isinstance(samples[0], list): + self.samples = np.array([complex(sample[0], sample[1]) for sample in samples]) + else: + self.samples = samples + + def to_dict(self): + """Return a dictionary format representation of the pulse library item. + + Returns: + dict: The dictionary form of the PulseLibraryItem. + """ + return {"name": self.name, "samples": self.samples} + + @classmethod + def from_dict(cls, data): + """Create a new PulseLibraryItem object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + PulseLibraryItem: The object from the input dictionary. + """ + return cls(**data) + + def __repr__(self): + return f"PulseLibraryItem({self.name}, {repr(self.samples)})" + + def __str__(self): + return f"Pulse Library Item:\n\tname: {self.name}\n\tsamples: {self.samples}" + + def __eq__(self, other): + if isinstance(other, PulseLibraryItem): + if self.to_dict() == other.to_dict(): + return True + return False + + +class PulseQobjInstruction: + """Internal - A class representing a single instruction in a PulseQobj Experiment.""" + + # Copy from the deprecated from qiskit.qobj.PulseQobjInstruction + + _COMMON_ATTRS = [ + "ch", + "conditional", + "val", + "phase", + "frequency", + "duration", + "qubits", + "memory_slot", + "register_slot", + "label", + "type", + "pulse_shape", + "parameters", + ] + + def __init__( + self, + name, + t0, + ch=None, + conditional=None, + val=None, + phase=None, + duration=None, + qubits=None, + memory_slot=None, + register_slot=None, + kernels=None, + discriminators=None, + label=None, + type=None, # pylint: disable=invalid-name,redefined-builtin + pulse_shape=None, + parameters=None, + frequency=None, + ): + """Instantiate a new PulseQobjInstruction object. + + Args: + name (str): The name of the instruction + t0 (int): Pulse start time in integer **dt** units. + ch (str): The channel to apply the pulse instruction. + conditional (int): The register to use for a conditional for this + instruction + val (complex): Complex value to apply, bounded by an absolute value + of 1. + phase (float): if a ``fc`` instruction, the frame change phase in + radians. + frequency (float): if a ``sf`` instruction, the frequency in Hz. + duration (int): The duration of the pulse in **dt** units. + qubits (list): A list of ``int`` representing the qubits the + instruction operates on + memory_slot (list): If a ``measure`` instruction this is a list + of ``int`` containing the list of memory slots to store the + measurement results in (must be the same length as qubits). + If a ``bfunc`` instruction this is a single ``int`` of the + memory slot to store the boolean function result in. + register_slot (list): If a ``measure`` instruction this is a list + of ``int`` containing the list of register slots in which to + store the measurement results (must be the same length as + qubits). If a ``bfunc`` instruction this is a single ``int`` + of the register slot in which to store the result. + kernels (list): List of :class:`QobjMeasurementOption` objects + defining the measurement kernels and set of parameters if the + measurement level is 1 or 2. Only used for ``acquire`` + instructions. + discriminators (list): A list of :class:`QobjMeasurementOption` + used to set the discriminators to be used if the measurement + level is 2. Only used for ``acquire`` instructions. + label (str): Label of instruction + type (str): Type of instruction + pulse_shape (str): The shape of the parametric pulse + parameters (dict): The parameters for a parametric pulse + """ + self.name = name + self.t0 = t0 + if ch is not None: + self.ch = ch + if conditional is not None: + self.conditional = conditional + if val is not None: + self.val = val + if phase is not None: + self.phase = phase + if frequency is not None: + self.frequency = frequency + if duration is not None: + self.duration = duration + if qubits is not None: + self.qubits = qubits + if memory_slot is not None: + self.memory_slot = memory_slot + if register_slot is not None: + self.register_slot = register_slot + if kernels is not None: + self.kernels = kernels + if discriminators is not None: + self.discriminators = discriminators + if label is not None: + self.label = label + if type is not None: + self.type = type + if pulse_shape is not None: + self.pulse_shape = pulse_shape + if parameters is not None: + self.parameters = parameters + + def to_dict(self): + """Return a dictionary format representation of the Instruction. + + Returns: + dict: The dictionary form of the PulseQobjInstruction. + """ + out_dict = {"name": self.name, "t0": self.t0} + for attr in self._COMMON_ATTRS: + if hasattr(self, attr): + out_dict[attr] = getattr(self, attr) + if hasattr(self, "kernels"): + out_dict["kernels"] = [x.to_dict() for x in self.kernels] + if hasattr(self, "discriminators"): + out_dict["discriminators"] = [x.to_dict() for x in self.discriminators] + return out_dict + + def __repr__(self): + out = f'PulseQobjInstruction(name="{self.name}", t0={self.t0}' + for attr in self._COMMON_ATTRS: + attr_val = getattr(self, attr, None) + if attr_val is not None: + if isinstance(attr_val, str): + out += f', {attr}="{attr_val}"' + else: + out += f", {attr}={attr_val}" + out += ")" + return out + + def __str__(self): + out = f"Instruction: {self.name}\n" + out += f"\t\tt0: {self.t0}\n" + for attr in self._COMMON_ATTRS: + if hasattr(self, attr): + out += f"\t\t{attr}: {getattr(self, attr)}\n" + return out + + @classmethod + def from_dict(cls, data): + """Create a new PulseQobjExperimentConfig object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + PulseQobjInstruction: The object from the input dictionary. + """ + schema = { + "discriminators": QobjMeasurementOption, + "kernels": QobjMeasurementOption, + } + skip = ["t0", "name"] + + # Pulse instruction data is nested dictionary. + # To avoid deepcopy and avoid mutating the source object, create new dict here. + in_data = {} + for key, value in data.items(): + if key in skip: + continue + if key == "parameters": + # This is flat dictionary of parametric pulse parameters + formatted_value = value.copy() + if "amp" in formatted_value: + formatted_value["amp"] = _to_complex(formatted_value["amp"]) + in_data[key] = formatted_value + continue + if key in schema: + if isinstance(value, list): + in_data[key] = list(map(schema[key].from_dict, value)) + else: + in_data[key] = schema[key].from_dict(value) + else: + in_data[key] = value + + return cls(data["name"], data["t0"], **in_data) + + def __eq__(self, other): + if isinstance(other, PulseQobjInstruction): + if self.to_dict() == other.to_dict(): + return True + return False + + +def _pulse_library(): + # The number of samples determines the pulse durations of the corresponding + # instructions. This default defines pulses with durations in multiples of + # 16 dt for consistency with the pulse granularity of real IBM devices, but + # keeps the number smaller than what would be realistic for + # manageability. If needed, more realistic durations could be added in the + # future (order of 160dt for 1q gates, 1760dt for 2q gates and measure). + return [ + PulseLibraryItem( + name="pulse_1", samples=np.linspace(0, 1.0, 16, dtype=np.complex128) + ), # 16dt + PulseLibraryItem( + name="pulse_2", samples=np.linspace(0, 1.0, 32, dtype=np.complex128) + ), # 32dt + PulseLibraryItem( + name="pulse_3", samples=np.linspace(0, 1.0, 64, dtype=np.complex128) + ), # 64dt + ] class GenericBackendV2(BackendV2): @@ -262,7 +678,7 @@ def _get_calibration_sequence( acting on qargs. """ - pulse_library = _PULSE_LIBRARY + pulse_library = _pulse_library() # Note that the calibration pulses are different for # 1q gates vs 2q gates vs measurement instructions. if inst == "measure": @@ -352,7 +768,7 @@ def _generate_calibration_defaults(self) -> PulseDefaults: qubit_freq_est=qubit_freq_est, meas_freq_est=meas_freq_est, buffer=0, - pulse_library=_PULSE_LIBRARY, + pulse_library=_pulse_library(), cmd_def=cmd_def, ) diff --git a/qiskit/providers/models/__init__.py b/qiskit/providers/models/__init__.py index d9e63e3eb75c..d7f8307abb04 100644 --- a/qiskit/providers/models/__init__.py +++ b/qiskit/providers/models/__init__.py @@ -38,26 +38,52 @@ GateProperties Nduv """ +# pylint: disable=undefined-all-variable +__all__ = [ + "BackendConfiguration", + "PulseBackendConfiguration", + "QasmBackendConfiguration", + "UchannelLO", + "GateConfig", + "BackendProperties", + "GateProperties", + "Nduv", + "BackendStatus", + "JobStatus", + "PulseDefaults", + "Command", +] + +import importlib import warnings -from .backendconfiguration import ( - BackendConfiguration, - PulseBackendConfiguration, - QasmBackendConfiguration, - UchannelLO, - GateConfig, -) -from .backendproperties import BackendProperties, GateProperties, Nduv -from .backendstatus import BackendStatus -from .jobstatus import JobStatus -from .pulsedefaults import PulseDefaults, Command - - -warnings.warn( - "qiskit.providers.models is deprecated since Qiskit 1.2 and will be removed in Qiskit 2.0. " - "With the removal of Qobj, there is no need for these schema-conformant objects. If you still need " - "to use them, it could be because you are using a BackendV1, which is also deprecated in favor " - "of BackendV2.", - DeprecationWarning, - 2, -) + +_NAME_MAP = { + # public object name mapped to containing module + "BackendConfiguration": "qiskit.providers.models.backendconfiguration", + "PulseBackendConfiguration": "qiskit.providers.models.backendconfiguration", + "QasmBackendConfiguration": "qiskit.providers.models.backendconfiguration", + "UchannelLO": "qiskit.providers.models.backendconfiguration", + "GateConfig": "qiskit.providers.models.backendconfiguration", + "BackendProperties": "qiskit.providers.models.backendproperties", + "GateProperties": "qiskit.providers.models.backendproperties", + "Nduv": "qiskit.providers.models.backendproperties", + "BackendStatus": "qiskit.providers.models.backendstatus", + "JobStatus": "qiskit.providers.models.jobstatus", + "PulseDefaults": "qiskit.providers.models.pulsedefaults", + "Command": "qiskit.providers.models.pulsedefaults", +} + + +def __getattr__(name): + if (module_name := _NAME_MAP.get(name)) is not None: + warnings.warn( + "qiskit.providers.models is deprecated since Qiskit 1.2 and will be " + "removed in Qiskit 2.0. With the removal of Qobj, there is no need for these " + "schema-conformant objects. If you still need to use them, it could be because " + "you are using a BackendV1, which is also deprecated in favor of BackendV2.", + DeprecationWarning, + stacklevel=2, + ) + return getattr(importlib.import_module(module_name), name) + raise AttributeError(f"module 'qiskit.providers.models' has no attribute '{name}'") diff --git a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py index 1ce2f2800c09..4054a158d12a 100644 --- a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py @@ -54,7 +54,7 @@ from qiskit.converters import circuit_to_dag, dag_to_circuit from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode from qiskit.exceptions import QiskitError -from qiskit.providers.models import BackendProperties +from qiskit.providers.models.backendproperties import BackendProperties from qiskit.quantum_info import Operator from qiskit.synthesis.one_qubit import one_qubit_decompose from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments diff --git a/test/benchmarks/pulse/load_pulse_defaults.py b/test/benchmarks/pulse/load_pulse_defaults.py index 1b7fa5cc1719..770ac1563b2b 100644 --- a/test/benchmarks/pulse/load_pulse_defaults.py +++ b/test/benchmarks/pulse/load_pulse_defaults.py @@ -15,7 +15,7 @@ import numpy as np -from qiskit.providers.models import PulseDefaults +from qiskit.providers.models.pulsedefaults import PulseDefaults from qiskit.compiler import schedule from qiskit.circuit import QuantumCircuit, Gate diff --git a/test/python/providers/faulty_backends.py b/test/python/providers/faulty_backends.py index f57cf1b594c3..ec8ba8fed594 100644 --- a/test/python/providers/faulty_backends.py +++ b/test/python/providers/faulty_backends.py @@ -12,7 +12,7 @@ """Faulty fake backends for testing""" -from qiskit.providers.models import BackendProperties +from qiskit.providers.models.backendproperties import BackendProperties from qiskit.providers.fake_provider import Fake7QPulseV1 diff --git a/test/python/providers/test_backendstatus.py b/test/python/providers/test_backendstatus.py index 2cfa31791de3..c0cfb7f792a3 100644 --- a/test/python/providers/test_backendstatus.py +++ b/test/python/providers/test_backendstatus.py @@ -14,7 +14,7 @@ """ from qiskit.providers.fake_provider import Fake5QV1 -from qiskit.providers.models import BackendStatus +from qiskit.providers.models.backendstatus import BackendStatus from test import QiskitTestCase # pylint: disable=wrong-import-order diff --git a/test/python/providers/test_fake_backends.py b/test/python/providers/test_fake_backends.py index 6d8716359bcc..3df3e7d5893f 100644 --- a/test/python/providers/test_fake_backends.py +++ b/test/python/providers/test_fake_backends.py @@ -37,8 +37,8 @@ ) from qiskit.providers.backend_compat import BackendV2Converter, convert_to_target from qiskit.providers.models.backendproperties import BackendProperties +from qiskit.providers.models.backendconfiguration import GateConfig from qiskit.providers.backend import BackendV2 -from qiskit.providers.models import GateConfig from qiskit.utils import optionals from qiskit.circuit.library import ( SXGate, diff --git a/test/python/transpiler/test_pulse_gate_pass.py b/test/python/transpiler/test_pulse_gate_pass.py index 07d6172264d4..1dd42d662860 100644 --- a/test/python/transpiler/test_pulse_gate_pass.py +++ b/test/python/transpiler/test_pulse_gate_pass.py @@ -16,7 +16,7 @@ from qiskit import pulse, circuit, transpile from qiskit.providers.fake_provider import Fake27QPulseV1, GenericBackendV2 -from qiskit.providers.models import GateConfig +from qiskit.providers.models.backendconfiguration import GateConfig from qiskit.quantum_info.random import random_unitary from test import QiskitTestCase # pylint: disable=wrong-import-order diff --git a/test/utils/base.py b/test/utils/base.py index 78d5aceb58f2..e1b2180aac4e 100644 --- a/test/utils/base.py +++ b/test/utils/base.py @@ -134,7 +134,7 @@ def setUpClass(cls): warnings.filterwarnings( "ignore", # If "default", it floods the CI output category=DeprecationWarning, - message=r"The class ``qiskit\.providers\.models\..*`", + message=r".*qiskit\.providers\.models.*", module=r"qiskit_aer(\.[a-zA-Z0-9_]+)*", ) From 76eb568c14f79ab9dad17d61c49380a5c7ef5e85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:46:41 +0000 Subject: [PATCH 03/85] Bump bytemuck from 1.16.3 to 1.17.0 (#12967) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.16.3 to 1.17.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.16.3...v1.17.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a590fc1fd9f..8ee13b9ff509 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.16.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" dependencies = [ "bytemuck_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 13ea3ead5584..f6141f787fdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ license = "Apache-2.0" # # Each crate can add on specific features freely as it inherits. [workspace.dependencies] -bytemuck = "1.16" +bytemuck = "1.17" indexmap.version = "2.4.0" hashbrown.version = "0.14.0" num-bigint = "0.4" From 06392c523fdc514d2592ffc489e7a3515049eba3 Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Mon, 19 Aug 2024 16:38:57 +0300 Subject: [PATCH 04/85] adding copy argument to __array__ (#12979) --- qiskit/circuit/library/basis_change/qft.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit/circuit/library/basis_change/qft.py b/qiskit/circuit/library/basis_change/qft.py index 2ec6dd69cb79..15668ec51e11 100644 --- a/qiskit/circuit/library/basis_change/qft.py +++ b/qiskit/circuit/library/basis_change/qft.py @@ -315,8 +315,10 @@ def __init__( """ super().__init__(name="qft", num_qubits=num_qubits, params=[]) - def __array__(self, dtype=complex): + def __array__(self, dtype=complex, copy=None): """Return a numpy array for the QFTGate.""" + if copy is False: + raise ValueError("unable to avoid copy while creating an array as requested") n = self.num_qubits nums = np.arange(2**n) outer = np.outer(nums, nums) From 3981a84e74a206e0f85323a8bc97d1853c8da46b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:10:40 +0000 Subject: [PATCH 05/85] Bump pulp from 0.18.21 to 0.18.22 (#12981) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [pulp](https://github.com/sarah-ek/pulp) from 0.18.21 to 0.18.22. - [Commits](https://github.com/sarah-ek/pulp/commits) --- updated-dependencies: - dependency-name: pulp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/accelerate/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ee13b9ff509..63e36f18645c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1052,9 +1052,9 @@ dependencies = [ [[package]] name = "pulp" -version = "0.18.21" +version = "0.18.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec8d02258294f59e4e223b41ad7e81c874aa6b15bc4ced9ba3965826da0eed5" +checksum = "a0a01a0dc67cf4558d279f0c25b0962bd08fc6dec0137699eae304103e882fe6" dependencies = [ "bytemuck", "libm", diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index 854c1ed05706..c93e81b14dee 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -54,5 +54,5 @@ version = "0.2.0" features = ["ndarray"] [dependencies.pulp] -version = "0.18.21" +version = "0.18.22" features = ["macro"] From 66fb6fee64ca9113417bd51f904a66509be7a9d8 Mon Sep 17 00:00:00 2001 From: ebaeumer <48065247+ebaeumer@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:41:25 +0200 Subject: [PATCH 06/85] Example code for Store instruction (#12982) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Example code for Store function * update shortened line * Update qiskit/circuit/__init__.py --------- Co-authored-by: Luciano Bello Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- qiskit/circuit/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/qiskit/circuit/__init__.py b/qiskit/circuit/__init__.py index 65a88519a0de..1ab084ef2072 100644 --- a/qiskit/circuit/__init__.py +++ b/qiskit/circuit/__init__.py @@ -579,6 +579,16 @@ :class:`Qubit` nor :class:`Clbit` operands, but has an explicit :attr:`~Store.lvalue` and :attr:`~Store.rvalue`. +For example, to determine the parity of a bitstring ``cr`` and store it in another register ``creg``, +the :class:`Store` instruction can be used in the following way:: + + parity = expr.lift(cr[0]) + for i in range(1,n): + parity = expr.bit_xor(cr[i], parity) + qc.store(creg[0], parity) + + + .. autoclass:: Store :show-inheritance: :members: From 393fb595178567d11a534a0d9da699b0fa15d565 Mon Sep 17 00:00:00 2001 From: jschuhmac <74537145+jschuhmac@users.noreply.github.com> Date: Mon, 19 Aug 2024 19:08:02 +0200 Subject: [PATCH 07/85] Add code example in Operator docstring. (#12985) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- qiskit/quantum_info/operators/operator.py | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index a4e93f364809..42593626f2cc 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -55,6 +55,30 @@ class Operator(LinearOp): .. math:: \rho \mapsto M \rho M^\dagger. + + For example, the following operator :math:`M = X` applied to the zero state + :math:`|\psi\rangle=|0\rangle (\rho = |0\rangle\langle 0|)` changes it to the + one state :math:`|\psi\rangle=|1\rangle (\rho = |1\rangle\langle 1|)`: + + .. code-block:: python + + >>> import numpy as np + >>> from qiskit.quantum_info import Operator + >>> op = Operator(np.array([[0.0, 1.0], [1.0, 0.0]])) # Represents Pauli X operator + + >>> from qiskit.quantum_info import Statevector + >>> sv = Statevector(np.array([1.0, 0.0])) + >>> sv.evolve(op) + Statevector([0.+0.j, 1.+0.j], + dims=(2,)) + + >>> from qiskit.quantum_info import DensityMatrix + >>> dm = DensityMatrix(np.array([[1.0, 0.0], [0.0, 0.0]])) + >>> dm.evolve(op) + DensityMatrix([[0.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j]], + dims=(2,)) + """ def __init__( From 59630272672e4593e2bd5570680e47961d398923 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Mon, 19 Aug 2024 19:39:35 +0200 Subject: [PATCH 08/85] fix stateprep's normalize (#12988) --- .../library/data_preparation/state_preparation.py | 2 +- .../fix-stateprep-normalize-a8057c339ba619bd.yaml | 6 ++++++ test/python/circuit/library/test_state_preparation.py | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix-stateprep-normalize-a8057c339ba619bd.yaml diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index 26c37334cfe4..df69f9eab8c5 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -173,7 +173,7 @@ def _define_synthesis_isom(self): q = QuantumRegister(self.num_qubits, "q") initialize_circuit = QuantumCircuit(q, name="init_def") - isom = Isometry(self._params_arg, 0, 0) + isom = Isometry(self.params, 0, 0) initialize_circuit.append(isom, q[:]) # invert the circuit to create the desired vector from zero (assuming diff --git a/releasenotes/notes/fix-stateprep-normalize-a8057c339ba619bd.yaml b/releasenotes/notes/fix-stateprep-normalize-a8057c339ba619bd.yaml new file mode 100644 index 000000000000..0175f8c1c026 --- /dev/null +++ b/releasenotes/notes/fix-stateprep-normalize-a8057c339ba619bd.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed a bug in :class:`.StatePreparation` where the ``normalize`` + argument was ignored for input arrays. + Fixed `#12984 `__. diff --git a/test/python/circuit/library/test_state_preparation.py b/test/python/circuit/library/test_state_preparation.py index adad848a2777..b5446ed37e9c 100644 --- a/test/python/circuit/library/test_state_preparation.py +++ b/test/python/circuit/library/test_state_preparation.py @@ -113,6 +113,16 @@ def test_repeats(self): qc.append(StatePreparation("01").repeat(2), [0, 1]) self.assertEqual(qc.decompose().count_ops()["state_preparation"], 2) + def test_normalize(self): + """Test the normalization. + + Regression test of #12984. + """ + qc = QuantumCircuit(1) + qc.compose(StatePreparation([1, 1], normalize=True), range(1), inplace=True) + + self.assertTrue(Statevector(qc).equiv(np.array([1, 1]) / np.sqrt(2))) + if __name__ == "__main__": unittest.main() From 5c8edd404060eb5186fe55f3874e35617253d55e Mon Sep 17 00:00:00 2001 From: jschuhmac <74537145+jschuhmac@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:56:12 +0200 Subject: [PATCH 09/85] Parsing of `seed_transpiler` in `generate_preset_pass_manager` (#12980) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Raise ValueError if seed_transpiler is negative * Fix code formatting * Implement suggested changes * Update releasenotes/notes/fix-negative-seed-pm-2813a62a020da115.yaml Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- .../generate_preset_pass_manager.py | 9 +++++++++ .../notes/fix-negative-seed-pm-2813a62a020da115.yaml | 4 ++++ test/python/transpiler/test_preset_passmanagers.py | 12 ++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 releasenotes/notes/fix-negative-seed-pm-2813a62a020da115.yaml diff --git a/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py b/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py index 353ad8c50b15..830618845352 100644 --- a/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +++ b/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py @@ -358,6 +358,7 @@ def generate_preset_pass_manager( # Parse non-target dependent pm options initial_layout = _parse_initial_layout(initial_layout) approximation_degree = _parse_approximation_degree(approximation_degree) + seed_transpiler = _parse_seed_transpiler(seed_transpiler) pm_options = { "target": target, @@ -532,3 +533,11 @@ def _parse_approximation_degree(approximation_degree): if approximation_degree < 0.0 or approximation_degree > 1.0: raise TranspilerError("Approximation degree must be in [0.0, 1.0]") return approximation_degree + + +def _parse_seed_transpiler(seed_transpiler): + if seed_transpiler is None: + return None + if not isinstance(seed_transpiler, int) or seed_transpiler < 0: + raise ValueError("Expected non-negative integer as seed for transpiler.") + return seed_transpiler diff --git a/releasenotes/notes/fix-negative-seed-pm-2813a62a020da115.yaml b/releasenotes/notes/fix-negative-seed-pm-2813a62a020da115.yaml new file mode 100644 index 000000000000..352f068537e8 --- /dev/null +++ b/releasenotes/notes/fix-negative-seed-pm-2813a62a020da115.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + Fixed the behavior of :meth:`.generate_preset_pass_manager` to raise a `ValueError` exception if not provided with a non-negative integer `seed_transpiler` argument. diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index aa689b4c4fee..dd760b2264ce 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -1529,6 +1529,18 @@ def test_generate_preset_pass_manager_with_list_initial_layout(self, optimizatio self.assertIsInstance(pm_object, PassManager) self.assertEqual(tqc_list, tqc_obj) + def test_parse_seed_transpiler_raises_value_error(self): + """Test that seed for transpiler is non-negative integer.""" + with self.assertRaisesRegex( + ValueError, "Expected non-negative integer as seed for transpiler." + ): + generate_preset_pass_manager(optimization_level=1, seed_transpiler=-1) + + with self.assertRaisesRegex( + ValueError, "Expected non-negative integer as seed for transpiler." + ): + generate_preset_pass_manager(seed_transpiler=0.1) + @ddt class TestIntegrationControlFlow(QiskitTestCase): From a11e76ca7d775824b0790cc1804846e089ed973b Mon Sep 17 00:00:00 2001 From: Joseph Loftin <65878716+jlofti@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:54:23 +0200 Subject: [PATCH 10/85] Port `synth_cz_depth_line_mr` to Rust (#12949) * First pass, pre cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * optimizations and cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * more cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * broke out function Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * reformat Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * comments for append_cx Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * correct usize usage Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * added _inner to function name Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * changed directory structure Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * port _append_reverse_permutation_lnn_kms Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * concise function, added sdg comment, all to usize Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * port synth_permutation_reverse_lnn_kms to rust Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * cleanup Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * readded Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * release notes and simplified comment Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * Update releasenotes/notes/port-synth-cz-depth-line-mr-to-rust-1376d5a41948112a.yaml Co-authored-by: Alexander Ivrii * promoted to docstring and added new docstrings Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> * Update crates/accelerate/src/synthesis/linear_phase/cz_depth_lnn.rs Co-authored-by: Julien Gacon --------- Signed-off-by: jlofti <65878716+jlofti@users.noreply.github.com> Co-authored-by: Alexander Ivrii Co-authored-by: Julien Gacon --- .../synthesis/linear_phase/cz_depth_lnn.rs | 171 ++++++++++++++++++ .../src/synthesis/linear_phase/mod.rs | 46 +++++ crates/accelerate/src/synthesis/mod.rs | 5 + .../src/synthesis/permutation/mod.rs | 73 ++++++++ qiskit/__init__.py | 1 + qiskit/synthesis/linear_phase/cz_depth_lnn.py | 148 +-------------- .../permutation/permutation_reverse_lnn.py | 9 +- ...epth-line-mr-to-rust-1376d5a41948112a.yaml | 6 + 8 files changed, 312 insertions(+), 147 deletions(-) create mode 100644 crates/accelerate/src/synthesis/linear_phase/cz_depth_lnn.rs create mode 100644 crates/accelerate/src/synthesis/linear_phase/mod.rs create mode 100644 releasenotes/notes/port-synth-cz-depth-line-mr-to-rust-1376d5a41948112a.yaml diff --git a/crates/accelerate/src/synthesis/linear_phase/cz_depth_lnn.rs b/crates/accelerate/src/synthesis/linear_phase/cz_depth_lnn.rs new file mode 100644 index 000000000000..df01c1ed6fa8 --- /dev/null +++ b/crates/accelerate/src/synthesis/linear_phase/cz_depth_lnn.rs @@ -0,0 +1,171 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use std::iter::once; + +use hashbrown::HashMap; +use itertools::Itertools; +use ndarray::{Array1, ArrayView2}; + +use qiskit_circuit::{ + operations::{Param, StandardGate}, + Qubit, +}; +use smallvec::{smallvec, SmallVec}; + +use crate::synthesis::permutation::{_append_cx_stage1, _append_cx_stage2}; + +// A sequence of Lnn gates +// Represents the return type for Lnn Synthesis algorithms +pub(crate) type LnnGatesVec = Vec<(StandardGate, SmallVec<[Param; 3]>, SmallVec<[Qubit; 2]>)>; + +/// A pattern denoted by Pj in [1] for odd number of qubits: +/// [n-2, n-4, n-4, ..., 3, 3, 1, 1, 0, 0, 2, 2, ..., n-3, n-3] +fn _odd_pattern1(n: usize) -> Vec { + once(n - 2) + .chain((0..((n - 3) / 2)).flat_map(|i| [(n - 2 * i - 4); 2])) + .chain((0..((n - 1) / 2)).flat_map(|i| [2 * i; 2])) + .collect() +} + +/// A pattern denoted by Pk in [1] for odd number of qubits: +/// [2, 2, 4, 4, ..., n-1, n-1, n-2, n-2, n-4, n-4, ..., 5, 5, 3, 3, 1] +fn _odd_pattern2(n: usize) -> Vec { + (0..((n - 1) / 2)) + .flat_map(|i| [(2 * i + 2); 2]) + .chain((0..((n - 3) / 2)).flat_map(|i| [n - 2 * i - 2; 2])) + .chain(once(1)) + .collect() +} + +/// A pattern denoted by Pj in [1] for even number of qubits: +/// [n-1, n-3, n-3, n-5, n-5, ..., 1, 1, 0, 0, 2, 2, ..., n-4, n-4, n-2] +fn _even_pattern1(n: usize) -> Vec { + once(n - 1) + .chain((0..((n - 2) / 2)).flat_map(|i| [n - 2 * i - 3; 2])) + .chain((0..((n - 2) / 2)).flat_map(|i| [2 * i; 2])) + .chain(once(n - 2)) + .collect() +} + +/// A pattern denoted by Pk in [1] for even number of qubits: +/// [2, 2, 4, 4, ..., n-2, n-2, n-1, n-1, ..., 3, 3, 1, 1] +fn _even_pattern2(n: usize) -> Vec { + (0..((n - 2) / 2)) + .flat_map(|i| [2 * (i + 1); 2]) + .chain((0..(n / 2)).flat_map(|i| [(n - 2 * i - 1); 2])) + .collect() +} + +/// Creating the patterns for the phase layers. +fn _create_patterns(n: usize) -> HashMap<(usize, usize), (usize, usize)> { + let (pat1, pat2) = if n % 2 == 0 { + (_even_pattern1(n), _even_pattern2(n)) + } else { + (_odd_pattern1(n), _odd_pattern2(n)) + }; + + let ind = if n % 2 == 0 { + (2 * n - 4) / 2 + } else { + (2 * n - 4) / 2 - 1 + }; + + HashMap::from_iter((0..n).map(|i| ((0, i), (i, i))).chain( + (0..(n / 2)).cartesian_product(0..n).map(|(layer, i)| { + ( + (layer + 1, i), + (pat1[ind - (2 * layer) + i], pat2[(2 * layer) + i]), + ) + }), + )) +} + +/// Appends correct phase gate during CZ synthesis +fn _append_phase_gate(pat_val: usize, gates: &mut LnnGatesVec, qubit: usize) { + // Add phase gates: s, sdg or z + let gate_id = pat_val % 4; + if gate_id != 0 { + let gate = match gate_id { + 1 => StandardGate::SdgGate, + 2 => StandardGate::ZGate, + 3 => StandardGate::SGate, + _ => unreachable!(), // unreachable as we have modulo 4 + }; + gates.push((gate, smallvec![], smallvec![Qubit(qubit as u32)])); + } +} + +/// Synthesis of a CZ circuit for linear nearest neighbor (LNN) connectivity, +/// based on Maslov and Roetteler. +pub(super) fn synth_cz_depth_line_mr_inner(matrix: ArrayView2) -> (usize, LnnGatesVec) { + let num_qubits = matrix.raw_dim()[0]; + let pats = _create_patterns(num_qubits); + + // s_gates[i] = 0, 1, 2 or 3 for a gate id, sdg, z or s on qubit i respectively + let mut s_gates = Array1::::zeros(num_qubits); + + let mut patlist: Vec<(usize, usize)> = Vec::new(); + + let mut gates = LnnGatesVec::new(); + + for i in 0..num_qubits { + for j in (i + 1)..num_qubits { + if matrix[[i, j]] { + // CZ(i,j) gate + s_gates[[i]] += 2; // qc.z[i] + s_gates[[j]] += 2; // qc.z[j] + patlist.push((i, j - 1)); + patlist.push((i, j)); + patlist.push((i + 1, j - 1)); + patlist.push((i + 1, j)); + } + } + } + + for i in 0..((num_qubits + 1) / 2) { + for j in 0..num_qubits { + let pat_val = pats[&(i, j)]; + if patlist.contains(&pat_val) { + // patcnt should be 0 or 1, which checks if a Sdg gate should be added + let patcnt = patlist.iter().filter(|val| **val == pat_val).count(); + s_gates[[j]] += patcnt; // qc.sdg[j] + } + + _append_phase_gate(s_gates[[j]], &mut gates, j) + } + + _append_cx_stage1(&mut gates, num_qubits); + _append_cx_stage2(&mut gates, num_qubits); + s_gates = Array1::::zeros(num_qubits); + } + + if num_qubits % 2 == 0 { + let i = num_qubits / 2; + + for j in 0..num_qubits { + let pat_val = pats[&(i, j)]; + if patlist.contains(&pat_val) && pat_val.0 != pat_val.1 { + // patcnt should be 0 or 1, which checks if a Sdg gate should be added + let patcnt = patlist.iter().filter(|val| **val == pat_val).count(); + + s_gates[[j]] += patcnt; // qc.sdg[j] + } + + _append_phase_gate(s_gates[[j]], &mut gates, j) + } + + _append_cx_stage1(&mut gates, num_qubits); + } + + (num_qubits, gates) +} diff --git a/crates/accelerate/src/synthesis/linear_phase/mod.rs b/crates/accelerate/src/synthesis/linear_phase/mod.rs new file mode 100644 index 000000000000..fd95985e1025 --- /dev/null +++ b/crates/accelerate/src/synthesis/linear_phase/mod.rs @@ -0,0 +1,46 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use numpy::PyReadonlyArray2; +use pyo3::{ + prelude::*, + pyfunction, + types::{PyModule, PyModuleMethods}, + wrap_pyfunction, Bound, PyResult, +}; +use qiskit_circuit::{circuit_data::CircuitData, operations::Param}; + +pub(crate) mod cz_depth_lnn; + +/// Synthesis of a CZ circuit for linear nearest neighbor (LNN) connectivity, +/// based on Maslov and Roetteler. +/// +/// Note that this method *reverts* the order of qubits in the circuit, +/// and returns a circuit containing :class:`.CXGate`\s and phase gates +/// (:class:`.SGate`, :class:`.SdgGate` or :class:`.ZGate`). +/// +/// References: +/// 1. Dmitri Maslov, Martin Roetteler, +/// *Shorter stabilizer circuits via Bruhat decomposition and quantum circuit transformations*, +/// `arXiv:1705.09176 `_. +#[pyfunction] +#[pyo3(signature = (mat))] +fn synth_cz_depth_line_mr(py: Python, mat: PyReadonlyArray2) -> PyResult { + let view = mat.as_array(); + let (num_qubits, lnn_gates) = cz_depth_lnn::synth_cz_depth_line_mr_inner(view); + CircuitData::from_standard_gates(py, num_qubits as u32, lnn_gates, Param::Float(0.0)) +} + +pub fn linear_phase(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(synth_cz_depth_line_mr))?; + Ok(()) +} diff --git a/crates/accelerate/src/synthesis/mod.rs b/crates/accelerate/src/synthesis/mod.rs index fae05c6739cc..6e22281e2250 100644 --- a/crates/accelerate/src/synthesis/mod.rs +++ b/crates/accelerate/src/synthesis/mod.rs @@ -12,6 +12,7 @@ mod clifford; pub mod linear; +pub mod linear_phase; mod permutation; use pyo3::prelude::*; @@ -21,6 +22,10 @@ pub fn synthesis(m: &Bound) -> PyResult<()> { linear::linear(&linear_mod)?; m.add_submodule(&linear_mod)?; + let linear_phase_mod = PyModule::new_bound(m.py(), "linear_phase")?; + linear_phase::linear_phase(&linear_phase_mod)?; + m.add_submodule(&linear_phase_mod)?; + let permutation_mod = PyModule::new_bound(m.py(), "permutation")?; permutation::permutation(&permutation_mod)?; m.add_submodule(&permutation_mod)?; diff --git a/crates/accelerate/src/synthesis/permutation/mod.rs b/crates/accelerate/src/synthesis/permutation/mod.rs index 55dc3efe4a87..2f84776cb5fd 100644 --- a/crates/accelerate/src/synthesis/permutation/mod.rs +++ b/crates/accelerate/src/synthesis/permutation/mod.rs @@ -20,6 +20,8 @@ use qiskit_circuit::circuit_data::CircuitData; use qiskit_circuit::operations::{Param, StandardGate}; use qiskit_circuit::Qubit; +use super::linear_phase::cz_depth_lnn::LnnGatesVec; + mod utils; /// Checks whether an array of size N is a permutation of 0, 1, ..., N - 1. @@ -114,11 +116,82 @@ pub fn _synth_permutation_depth_lnn_kms( ) } +/// A single layer of CX gates. +pub(crate) fn _append_cx_stage1(gates: &mut LnnGatesVec, n: usize) { + for i in 0..(n / 2) { + gates.push(( + StandardGate::CXGate, + smallvec![], + smallvec![Qubit((2 * i) as u32), Qubit((2 * i + 1) as u32)], + )) + } + + for i in 0..((n + 1) / 2 - 1) { + gates.push(( + StandardGate::CXGate, + smallvec![], + smallvec![Qubit((2 * i + 2) as u32), Qubit((2 * i + 1) as u32)], + )) + } +} + +/// A single layer of CX gates. +pub(crate) fn _append_cx_stage2(gates: &mut LnnGatesVec, n: usize) { + for i in 0..(n / 2) { + gates.push(( + StandardGate::CXGate, + smallvec![], + smallvec![Qubit((2 * i + 1) as u32), Qubit((2 * i) as u32)], + )) + } + + for i in 0..((n + 1) / 2 - 1) { + gates.push(( + StandardGate::CXGate, + smallvec![], + smallvec![Qubit((2 * i + 1) as u32), Qubit((2 * i + 2) as u32)], + )) + } +} + +/// Append reverse permutation to a QuantumCircuit for linear nearest-neighbor architectures +/// using Kutin, Moulton, Smithline method. +fn _append_reverse_permutation_lnn_kms(gates: &mut LnnGatesVec, num_qubits: usize) { + (0..(num_qubits + 1) / 2).for_each(|_| { + _append_cx_stage1(gates, num_qubits); + _append_cx_stage2(gates, num_qubits); + }); + + if num_qubits % 2 == 0 { + _append_cx_stage1(gates, num_qubits); + } +} + +/// Synthesize reverse permutation for linear nearest-neighbor architectures using +/// Kutin, Moulton, Smithline method. +/// +/// Synthesis algorithm for reverse permutation from [1], section 5. +/// This algorithm synthesizes the reverse permutation on :math:`n` qubits over +/// a linear nearest-neighbor architecture using CX gates with depth :math:`2 * n + 2`. +/// +/// References: +/// 1. Kutin, S., Moulton, D. P., Smithline, L., +/// *Computation at a distance*, Chicago J. Theor. Comput. Sci., vol. 2007, (2007), +/// `arXiv:quant-ph/0701194 `_ +#[pyfunction] +#[pyo3(signature = (num_qubits))] +fn synth_permutation_reverse_lnn_kms(py: Python, num_qubits: usize) -> PyResult { + let mut gates = LnnGatesVec::new(); + _append_reverse_permutation_lnn_kms(&mut gates, num_qubits); + CircuitData::from_standard_gates(py, num_qubits as u32, gates, Param::Float(0.0)) +} + pub fn permutation(m: &Bound) -> PyResult<()> { m.add_function(wrap_pyfunction!(_validate_permutation, m)?)?; m.add_function(wrap_pyfunction!(_inverse_pattern, m)?)?; m.add_function(wrap_pyfunction!(_synth_permutation_basic, m)?)?; m.add_function(wrap_pyfunction!(_synth_permutation_acg, m)?)?; m.add_function(wrap_pyfunction!(_synth_permutation_depth_lnn_kms, m)?)?; + m.add_function(wrap_pyfunction!(synth_permutation_reverse_lnn_kms, m)?)?; Ok(()) } diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 6091bfa90346..6a8df393307e 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -85,6 +85,7 @@ sys.modules["qiskit._accelerate.synthesis.permutation"] = _accelerate.synthesis.permutation sys.modules["qiskit._accelerate.synthesis.linear"] = _accelerate.synthesis.linear sys.modules["qiskit._accelerate.synthesis.clifford"] = _accelerate.synthesis.clifford +sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase from qiskit.exceptions import QiskitError, MissingOptionalLibraryError diff --git a/qiskit/synthesis/linear_phase/cz_depth_lnn.py b/qiskit/synthesis/linear_phase/cz_depth_lnn.py index 7a195f0caf96..419aec806f2e 100644 --- a/qiskit/synthesis/linear_phase/cz_depth_lnn.py +++ b/qiskit/synthesis/linear_phase/cz_depth_lnn.py @@ -24,98 +24,10 @@ import numpy as np from qiskit.circuit import QuantumCircuit -from qiskit.synthesis.permutation.permutation_reverse_lnn import ( - _append_cx_stage1, - _append_cx_stage2, -) - - -def _odd_pattern1(n): - """A pattern denoted by Pj in [1] for odd number of qubits: - [n-2, n-4, n-4, ..., 3, 3, 1, 1, 0, 0, 2, 2, ..., n-3, n-3] - """ - pat = [] - pat.append(n - 2) - for i in range((n - 3) // 2): - pat.append(n - 2 * i - 4) - pat.append(n - 2 * i - 4) - for i in range((n - 1) // 2): - pat.append(2 * i) - pat.append(2 * i) - return pat - - -def _odd_pattern2(n): - """A pattern denoted by Pk in [1] for odd number of qubits: - [2, 2, 4, 4, ..., n-1, n-1, n-2, n-2, n-4, n-4, ..., 5, 5, 3, 3, 1] - """ - pat = [] - for i in range((n - 1) // 2): - pat.append(2 * i + 2) - pat.append(2 * i + 2) - for i in range((n - 3) // 2): - pat.append(n - 2 * i - 2) - pat.append(n - 2 * i - 2) - pat.append(1) - return pat - - -def _even_pattern1(n): - """A pattern denoted by Pj in [1] for even number of qubits: - [n-1, n-3, n-3, n-5, n-5, ..., 1, 1, 0, 0, 2, 2, ..., n-4, n-4, n-2] - """ - pat = [] - pat.append(n - 1) - for i in range((n - 2) // 2): - pat.append(n - 2 * i - 3) - pat.append(n - 2 * i - 3) - for i in range((n - 2) // 2): - pat.append(2 * i) - pat.append(2 * i) - pat.append(n - 2) - return pat - -def _even_pattern2(n): - """A pattern denoted by Pk in [1] for even number of qubits: - [2, 2, 4, 4, ..., n-2, n-2, n-1, n-1, ..., 3, 3, 1, 1] - """ - pat = [] - for i in range((n - 2) // 2): - pat.append(2 * (i + 1)) - pat.append(2 * (i + 1)) - for i in range(n // 2): - pat.append(n - 2 * i - 1) - pat.append(n - 2 * i - 1) - return pat - - -def _create_patterns(n): - """Creating the patterns for the phase layers.""" - if (n % 2) == 0: - pat1 = _even_pattern1(n) - pat2 = _even_pattern2(n) - else: - pat1 = _odd_pattern1(n) - pat2 = _odd_pattern2(n) - pats = {} - - layer = 0 - for i in range(n): - pats[(0, i)] = (i, i) - - if (n % 2) == 0: - ind1 = (2 * n - 4) // 2 - else: - ind1 = (2 * n - 4) // 2 - 1 - ind2 = 0 - while layer < (n // 2): - for i in range(n): - pats[(layer + 1, i)] = (pat1[ind1 + i], pat2[ind2 + i]) - layer += 1 - ind1 -= 2 - ind2 += 2 - return pats +from qiskit._accelerate.synthesis.linear_phase import ( + synth_cz_depth_line_mr as synth_cz_depth_line_mr_inner, +) def synth_cz_depth_line_mr(mat: np.ndarray) -> QuantumCircuit: @@ -139,56 +51,6 @@ def synth_cz_depth_line_mr(mat: np.ndarray) -> QuantumCircuit: *Shorter stabilizer circuits via Bruhat decomposition and quantum circuit transformations*, `arXiv:1705.09176 `_. """ - num_qubits = mat.shape[0] - pats = _create_patterns(num_qubits) - patlist = [] - # s_gates[i] = 0, 1, 2 or 3 for a gate id, sdg, z or s on qubit i respectively - s_gates = np.zeros(num_qubits) - - qc = QuantumCircuit(num_qubits) - for i in range(num_qubits): - for j in range(i + 1, num_qubits): - if mat[i][j]: # CZ(i,j) gate - s_gates[i] += 2 # qc.z[i] - s_gates[j] += 2 # qc.z[j] - patlist.append((i, j - 1)) - patlist.append((i, j)) - patlist.append((i + 1, j - 1)) - patlist.append((i + 1, j)) - - for i in range((num_qubits + 1) // 2): - for j in range(num_qubits): - if pats[(i, j)] in patlist: - patcnt = patlist.count(pats[(i, j)]) - for _ in range(patcnt): - s_gates[j] += 1 # qc.sdg[j] - # Add phase gates: s, sdg or z - for j in range(num_qubits): - if s_gates[j] % 4 == 1: - qc.sdg(j) - elif s_gates[j] % 4 == 2: - qc.z(j) - elif s_gates[j] % 4 == 3: - qc.s(j) - qc = _append_cx_stage1(qc, num_qubits) - qc = _append_cx_stage2(qc, num_qubits) - s_gates = np.zeros(num_qubits) - - if (num_qubits % 2) == 0: - i = num_qubits // 2 - for j in range(num_qubits): - if pats[(i, j)] in patlist and pats[(i, j)][0] != pats[(i, j)][1]: - patcnt = patlist.count(pats[(i, j)]) - for _ in range(patcnt): - s_gates[j] += 1 # qc.sdg[j] - # Add phase gates: s, sdg or z - for j in range(num_qubits): - if s_gates[j] % 4 == 1: - qc.sdg(j) - elif s_gates[j] % 4 == 2: - qc.z(j) - elif s_gates[j] % 4 == 3: - qc.s(j) - qc = _append_cx_stage1(qc, num_qubits) - return qc + # Call Rust implementaton + return QuantumCircuit._from_circuit_data(synth_cz_depth_line_mr_inner(mat.astype(bool))) diff --git a/qiskit/synthesis/permutation/permutation_reverse_lnn.py b/qiskit/synthesis/permutation/permutation_reverse_lnn.py index 26287a06177e..f214fd7ce294 100644 --- a/qiskit/synthesis/permutation/permutation_reverse_lnn.py +++ b/qiskit/synthesis/permutation/permutation_reverse_lnn.py @@ -14,6 +14,9 @@ """ from qiskit.circuit import QuantumCircuit +from qiskit._accelerate.synthesis.permutation import ( + synth_permutation_reverse_lnn_kms as synth_permutation_reverse_lnn_kms_inner, +) def _append_cx_stage1(qc, n): @@ -84,7 +87,5 @@ def synth_permutation_reverse_lnn_kms(num_qubits: int) -> QuantumCircuit: `arXiv:quant-ph/0701194 `_ """ - qc = QuantumCircuit(num_qubits) - _append_reverse_permutation_lnn_kms(qc, num_qubits) - - return qc + # Call Rust implementation + return QuantumCircuit._from_circuit_data(synth_permutation_reverse_lnn_kms_inner(num_qubits)) diff --git a/releasenotes/notes/port-synth-cz-depth-line-mr-to-rust-1376d5a41948112a.yaml b/releasenotes/notes/port-synth-cz-depth-line-mr-to-rust-1376d5a41948112a.yaml new file mode 100644 index 000000000000..ee4c6933a269 --- /dev/null +++ b/releasenotes/notes/port-synth-cz-depth-line-mr-to-rust-1376d5a41948112a.yaml @@ -0,0 +1,6 @@ +--- +features_synthesis: + - | + Port :func: `.synth_cz_depth_line_mr` to Rust. This function synthesizes a CZ circuit for linear nearest neighbor (LNN) connectivity, based on the Maslov and Roetteler method. On a 350x350 binary matrix, the Rust implementation yields a speedup of about 30 times. + - | + Port :func: `.synth_permutation_reverse_lnn_kms` to Rust, which synthesizes a reverse permutation for linear nearest-neighbor architecture using the Kutin, Moulton, Smithline method. From d430e586f71d03e21fea7df6c5dbe4f73680ac1e Mon Sep 17 00:00:00 2001 From: QuantumDan Date: Tue, 20 Aug 2024 14:28:54 +0200 Subject: [PATCH 11/85] Deprecates `StochasticSwap` and suggests the use of `SabreSwap` (#12983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * first attempt to fix issue 12552 * first attempt to fix issue 12552 * fixed issue 12552 and unittest * formatted and completed 12552 * formatted and completed 12552 documentation * fixed unit tests 12552 * Update qiskit/transpiler/passes/routing/stochastic_swap.py Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * linted * passed all tests, including compiler test * final linting and unittest passing - hopefully * Update qiskit/transpiler/passes/routing/stochastic_swap.py Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * added test * Apply suggestions from code review --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- .../passes/routing/stochastic_swap.py | 8 + ...ecate-StochasticSwap-451f46b273602b7b.yaml | 46 +++ test/python/compiler/test_transpiler.py | 203 ++++++++++++- test/python/transpiler/test_mappers.py | 14 +- .../transpiler/test_preset_passmanagers.py | 5 +- test/python/transpiler/test_sabre_layout.py | 26 +- test/python/transpiler/test_stage_plugin.py | 27 +- .../python/transpiler/test_stochastic_swap.py | 287 ++++++++++-------- 8 files changed, 469 insertions(+), 147 deletions(-) create mode 100644 releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml diff --git a/qiskit/transpiler/passes/routing/stochastic_swap.py b/qiskit/transpiler/passes/routing/stochastic_swap.py index 3732802b770e..8cb628501017 100644 --- a/qiskit/transpiler/passes/routing/stochastic_swap.py +++ b/qiskit/transpiler/passes/routing/stochastic_swap.py @@ -38,6 +38,7 @@ from qiskit._accelerate import stochastic_swap as stochastic_swap_rs from qiskit._accelerate import nlayout from qiskit.transpiler.passes.layout import disjoint_utils +from qiskit.utils import deprecate_func from .utils import get_swap_map_dag @@ -59,6 +60,12 @@ class StochasticSwap(TransformationPass): the circuit. """ + @deprecate_func( + since="1.3", + removal_timeline="in the 2.0 release", + additional_msg="The `StochasticSwap` transpilation pass is a suboptimal " + "routing algorithm and has been superseded by the :class:`.SabreSwap` pass.", + ) def __init__(self, coupling_map, trials=20, seed=None, fake_run=False, initial_layout=None): """StochasticSwap initializer. @@ -76,6 +83,7 @@ def __init__(self, coupling_map, trials=20, seed=None, fake_run=False, initial_l initial_layout (Layout): starting layout at beginning of pass. """ super().__init__() + if isinstance(coupling_map, Target): self.target = coupling_map self.coupling_map = self.target.build_coupling_map() diff --git a/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml b/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml new file mode 100644 index 000000000000..24ade535f294 --- /dev/null +++ b/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml @@ -0,0 +1,46 @@ +--- +deprecations_transpiler: + - | + Deprecated ``StochasticSwap`` which has been superseded by :class:`.SabreSwap`. + If the class is called from the transpile function, the change would be, for example:: + + tqc = transpile( + circuit, + routing_method="stochastic", + layout_method="dense", + seed_transpiler=12342, + target=GenericBackendV2( + num_qubits=27, + coupling_map=MUMBAI_CMAP, + ).target, + ) + + to:: + + tqc = transpile( + circuit, + routing_method="sabre", + layout_method="sabre", + seed_transpiler=12342, + target=GenericBackendV2( + num_qubits=27, + coupling_map=MUMBAI_CMAP, + ).target, + ) + + While for a pass mananager change:: + + qr = QuantumRegister(4, "q") + qc = QuantumCircuit(qr) + passmanager = PassManager(StochasticSwap(coupling, 20, 13)) + new_qc = passmanager.run(qc) + + to:: + + qr = QuantumRegister(5, "q") + qc = QuantumCircuit(qr) + passmanager = PassManager(SabreSwap(target, "basic")) + new_qc = passmanager.run(qc) + + + diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index a348ad8b749d..c3a930aed1f2 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -928,7 +928,10 @@ def test_move_measurements(self): circ = QuantumCircuit.from_qasm_file(os.path.join(qasm_dir, "move_measurements.qasm")) lay = [0, 1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6] - out = transpile(circ, initial_layout=lay, coupling_map=cmap, routing_method="stochastic") + with self.assertWarns(DeprecationWarning): + out = transpile( + circ, initial_layout=lay, coupling_map=cmap, routing_method="stochastic" + ) out_dag = circuit_to_dag(out) meas_nodes = out_dag.named_nodes("measure") for meas_node in meas_nodes: @@ -3498,7 +3501,7 @@ def _visit_block(circuit, qubit_mapping=None): )[0] self.assertIn(qubit_map[op_node.qargs[0]], components[2]) - @data("sabre", "stochastic", "basic", "lookahead") + @data("sabre", "basic", "lookahead") def test_basic_connected_circuit_dense_layout(self, routing_method): """Test basic connected circuit on disjoint backend""" qc = QuantumCircuit(5) @@ -3522,8 +3525,34 @@ def test_basic_connected_circuit_dense_layout(self, routing_method): continue self.assertIn(qubits, self.backend.target[op_name]) + @data("stochastic") + def test_basic_connected_circuit_dense_layout_stochastic(self, routing_method): + """Test basic connected circuit on disjoint backend for deprecated stochastic swap""" + # TODO: Remove when StochasticSwap is removed + qc = QuantumCircuit(5) + qc.h(0) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.measure_all() + with self.assertWarns(DeprecationWarning): + tqc = transpile( + qc, + self.backend, + layout_method="dense", + routing_method=routing_method, + seed_transpiler=42, + ) + for inst in tqc.data: + qubits = tuple(tqc.find_bit(x).index for x in inst.qubits) + op_name = inst.operation.name + if op_name == "barrier": + continue + self.assertIn(qubits, self.backend.target[op_name]) + # Lookahead swap skipped for performance - @data("sabre", "stochastic", "basic") + @data("sabre", "basic") def test_triple_circuit_dense_layout(self, routing_method): """Test a split circuit with one circuit component per chip.""" qc = QuantumCircuit(30) @@ -3572,7 +3601,58 @@ def test_triple_circuit_dense_layout(self, routing_method): continue self.assertIn(qubits, self.backend.target[op_name]) - @data("sabre", "stochastic", "basic", "lookahead") + @data("stochastic") + def test_triple_circuit_dense_layout_stochastic(self, routing_method): + """Test a split circuit with one circuit component per chip for deprecated StochasticSwap.""" + # TODO: Remove when StochasticSwap is removed + qc = QuantumCircuit(30) + qc.h(0) + qc.h(10) + qc.h(20) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.cx(0, 5) + qc.cx(0, 6) + qc.cx(0, 7) + qc.cx(0, 8) + qc.cx(0, 9) + qc.ecr(10, 11) + qc.ecr(10, 12) + qc.ecr(10, 13) + qc.ecr(10, 14) + qc.ecr(10, 15) + qc.ecr(10, 16) + qc.ecr(10, 17) + qc.ecr(10, 18) + qc.ecr(10, 19) + qc.cy(20, 21) + qc.cy(20, 22) + qc.cy(20, 23) + qc.cy(20, 24) + qc.cy(20, 25) + qc.cy(20, 26) + qc.cy(20, 27) + qc.cy(20, 28) + qc.cy(20, 29) + qc.measure_all() + with self.assertWarns(DeprecationWarning): + tqc = transpile( + qc, + self.backend, + layout_method="dense", + routing_method=routing_method, + seed_transpiler=42, + ) + for inst in tqc.data: + qubits = tuple(tqc.find_bit(x).index for x in inst.qubits) + op_name = inst.operation.name + if op_name == "barrier": + continue + self.assertIn(qubits, self.backend.target[op_name]) + + @data("sabre", "basic", "lookahead") def test_triple_circuit_invalid_layout(self, routing_method): """Test a split circuit with one circuit component per chip.""" qc = QuantumCircuit(30) @@ -3616,8 +3696,54 @@ def test_triple_circuit_invalid_layout(self, routing_method): seed_transpiler=42, ) - # Lookahead swap skipped for performance reasons - @data("sabre", "stochastic", "basic") + @data("stochastic") + def test_triple_circuit_invalid_layout_stochastic(self, routing_method): + """Test a split circuit with one circuit component per chip for deprecated ``StochasticSwap``""" + # TODO: Remove when StochasticSwap is removed + qc = QuantumCircuit(30) + qc.h(0) + qc.h(10) + qc.h(20) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.cx(0, 5) + qc.cx(0, 6) + qc.cx(0, 7) + qc.cx(0, 8) + qc.cx(0, 9) + qc.ecr(10, 11) + qc.ecr(10, 12) + qc.ecr(10, 13) + qc.ecr(10, 14) + qc.ecr(10, 15) + qc.ecr(10, 16) + qc.ecr(10, 17) + qc.ecr(10, 18) + qc.ecr(10, 19) + qc.cy(20, 21) + qc.cy(20, 22) + qc.cy(20, 23) + qc.cy(20, 24) + qc.cy(20, 25) + qc.cy(20, 26) + qc.cy(20, 27) + qc.cy(20, 28) + qc.cy(20, 29) + qc.measure_all() + with self.assertWarns(DeprecationWarning): + with self.assertRaises(TranspilerError): + transpile( + qc, + self.backend, + layout_method="trivial", + routing_method=routing_method, + seed_transpiler=42, + ) + + # Lookahead swap skipped for performance reasons, stochastic moved to new test due to deprecation + @data("sabre", "basic") def test_six_component_circuit_dense_layout(self, routing_method): """Test input circuit with more than 1 component per backend component.""" qc = QuantumCircuit(42) @@ -3678,6 +3804,71 @@ def test_six_component_circuit_dense_layout(self, routing_method): continue self.assertIn(qubits, self.backend.target[op_name]) + # Lookahead swap skipped for performance reasons + @data("stochastic") + def test_six_component_circuit_dense_layout_stochastic(self, routing_method): + """Test input circuit with more than 1 component per backend component + for deprecated ``StochasticSwap``.""" + # TODO: Remove when StochasticSwap is removed + qc = QuantumCircuit(42) + qc.h(0) + qc.h(10) + qc.h(20) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.cx(0, 5) + qc.cx(0, 6) + qc.cx(0, 7) + qc.cx(0, 8) + qc.cx(0, 9) + qc.ecr(10, 11) + qc.ecr(10, 12) + qc.ecr(10, 13) + qc.ecr(10, 14) + qc.ecr(10, 15) + qc.ecr(10, 16) + qc.ecr(10, 17) + qc.ecr(10, 18) + qc.ecr(10, 19) + qc.cy(20, 21) + qc.cy(20, 22) + qc.cy(20, 23) + qc.cy(20, 24) + qc.cy(20, 25) + qc.cy(20, 26) + qc.cy(20, 27) + qc.cy(20, 28) + qc.cy(20, 29) + qc.h(30) + qc.cx(30, 31) + qc.cx(30, 32) + qc.cx(30, 33) + qc.h(34) + qc.cx(34, 35) + qc.cx(34, 36) + qc.cx(34, 37) + qc.h(38) + qc.cx(38, 39) + qc.cx(39, 40) + qc.cx(39, 41) + qc.measure_all() + with self.assertWarns(DeprecationWarning): + tqc = transpile( + qc, + self.backend, + layout_method="dense", + routing_method=routing_method, + seed_transpiler=42, + ) + for inst in tqc.data: + qubits = tuple(tqc.find_bit(x).index for x in inst.qubits) + op_name = inst.operation.name + if op_name == "barrier": + continue + self.assertIn(qubits, self.backend.target[op_name]) + @data(0, 1, 2, 3) def test_transpile_target_with_qubits_without_ops(self, opt_level): """Test qubits without operations aren't ever used.""" diff --git a/test/python/transpiler/test_mappers.py b/test/python/transpiler/test_mappers.py index dc4767b19517..c3b0644c2473 100644 --- a/test/python/transpiler/test_mappers.py +++ b/test/python/transpiler/test_mappers.py @@ -71,12 +71,13 @@ def test_a_common_test(self): import unittest import os import sys +import warnings from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit, transpile from qiskit.providers.basic_provider import BasicSimulator from qiskit.qasm2 import dump from qiskit.transpiler import PassManager -from qiskit.transpiler.passes import BasicSwap, LookaheadSwap, StochasticSwap, SabreSwap +from qiskit.transpiler.passes import BasicSwap, LookaheadSwap, SabreSwap, StochasticSwap from qiskit.transpiler.passes import SetLayout from qiskit.transpiler import CouplingMap, Layout from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -104,8 +105,15 @@ def create_passmanager(self, coupling_map, initial_layout=None): if initial_layout: passmanager.append(SetLayout(Layout(initial_layout))) - # pylint: disable=not-callable - passmanager.append(self.pass_class(CouplingMap(coupling_map), **self.additional_args)) + with warnings.catch_warnings(): + # TODO: remove this filter when StochasticSwap is removed + warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + message=r".*StochasticSwap.*", + ) + # pylint: disable=not-callable + passmanager.append(self.pass_class(CouplingMap(coupling_map), **self.additional_args)) return passmanager def create_backend(self): diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index dd760b2264ce..b762d84032bb 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -497,7 +497,7 @@ def test_level1_runs_vf2post_layout_when_routing_required(self): self.assertNotIn("SabreSwap", self.passes) def test_level1_runs_vf2post_layout_when_routing_method_set_and_required(self): - """Test that if we run routing as part of sabre layout VF2PostLayout runs.""" + """Test that if we run routing as part of sabre layout then VF2PostLayout runs.""" target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) qc = QuantumCircuit(5) qc.h(0) @@ -507,7 +507,7 @@ def test_level1_runs_vf2post_layout_when_routing_method_set_and_required(self): qc.cy(0, 4) qc.measure_all() _ = transpile( - qc, target, optimization_level=1, routing_method="stochastic", callback=self.callback + qc, target, optimization_level=1, routing_method="sabre", callback=self.callback ) # Expected call path for layout and routing is: # 1. TrivialLayout (no perfect match) @@ -518,7 +518,6 @@ def test_level1_runs_vf2post_layout_when_routing_method_set_and_required(self): self.assertIn("VF2Layout", self.passes) self.assertIn("SabreLayout", self.passes) self.assertIn("VF2PostLayout", self.passes) - self.assertIn("StochasticSwap", self.passes) def test_level1_not_runs_vf2post_layout_when_layout_method_set(self): """Test that if we don't run VF2PostLayout with custom layout_method.""" diff --git a/test/python/transpiler/test_sabre_layout.py b/test/python/transpiler/test_sabre_layout.py index 5ab8fe5c10b2..a5ebef43540f 100644 --- a/test/python/transpiler/test_sabre_layout.py +++ b/test/python/transpiler/test_sabre_layout.py @@ -259,14 +259,15 @@ def test_layout_many_search_trials(self): coupling_map=MUMBAI_CMAP, seed=42, ) - res = transpile( - qc, - backend, - layout_method="sabre", - routing_method="stochastic", - seed_transpiler=12345, - optimization_level=1, - ) + with self.assertWarns(DeprecationWarning): + res = transpile( + qc, + backend, + layout_method="sabre", + routing_method="stochastic", + seed_transpiler=12345, + optimization_level=1, + ) self.assertIsInstance(res, QuantumCircuit) layout = res._layout.initial_layout self.assertEqual( @@ -306,10 +307,11 @@ def test_support_var_with_explicit_routing_pass(self): qc.cx(4, 0) cm = CouplingMap.from_line(8) - pass_ = SabreLayout( - cm, seed=0, routing_pass=StochasticSwap(cm, trials=1, seed=0, fake_run=True) - ) - _ = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = SabreLayout( + cm, seed=0, routing_pass=StochasticSwap(cm, trials=1, seed=0, fake_run=True) + ) + _ = pass_(qc) layout = pass_.property_set["layout"] self.assertEqual([layout[q] for q in qc.qubits], [2, 3, 4, 1, 5]) diff --git a/test/python/transpiler/test_stage_plugin.py b/test/python/transpiler/test_stage_plugin.py index 1c0adc9776a0..f278096b8419 100644 --- a/test/python/transpiler/test_stage_plugin.py +++ b/test/python/transpiler/test_stage_plugin.py @@ -102,7 +102,7 @@ class TestBuiltinPlugins(QiskitTestCase): @combine( optimization_level=list(range(4)), - routing_method=["basic", "lookahead", "sabre", "stochastic"], + routing_method=["basic", "lookahead", "sabre"], ) def test_routing_plugins(self, optimization_level, routing_method): """Test all routing plugins (excluding error).""" @@ -123,6 +123,31 @@ def test_routing_plugins(self, optimization_level, routing_method): counts = backend.run(tqc, shots=1000).result().get_counts() self.assertDictAlmostEqual(counts, {"0000": 500, "1111": 500}, delta=100) + @combine( + optimization_level=list(range(4)), + routing_method=["stochastic"], + ) + def test_routing_plugin_stochastic(self, optimization_level, routing_method): + """Test stoc routing plugins (excluding error).""" + # Note remove once StochasticSwap gets removed + qc = QuantumCircuit(4) + qc.h(0) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.measure_all() + with self.assertWarns(DeprecationWarning): + tqc = transpile( + qc, + basis_gates=["cx", "sx", "x", "rz"], + coupling_map=CouplingMap.from_line(4), + optimization_level=optimization_level, + routing_method=routing_method, + ) + backend = BasicSimulator() + counts = backend.run(tqc, shots=1000).result().get_counts() + self.assertDictAlmostEqual(counts, {"0000": 500, "1111": 500}, delta=100) + @combine( optimization_level=list(range(4)), ) diff --git a/test/python/transpiler/test_stochastic_swap.py b/test/python/transpiler/test_stochastic_swap.py index 4843bac8baf5..ee5d8a1dad31 100644 --- a/test/python/transpiler/test_stochastic_swap.py +++ b/test/python/transpiler/test_stochastic_swap.py @@ -60,8 +60,9 @@ def test_trivial_case(self): circuit.cx(qr[0], qr[2]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) self.assertEqual(dag, after) @@ -83,8 +84,9 @@ def test_trivial_in_same_layer(self): circuit.cx(qr[0], qr[1]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) self.assertEqual(dag, after) @@ -109,8 +111,9 @@ def test_permute_wires_1(self): circuit.cx(qr[1], qr[2]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 11) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 11) + after = pass_.run(dag) expected = QuantumCircuit(qr) expected.swap(qr[0], qr[2]) @@ -140,8 +143,9 @@ def test_permute_wires_2(self): circuit.h(qr[0]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 11) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 11) + after = pass_.run(dag) expected = QuantumCircuit(qr) expected.swap(qr[1], qr[2]) @@ -176,8 +180,9 @@ def test_permute_wires_3(self): circuit.cx(qr[3], qr[0]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) expected = QuantumCircuit(qr) expected.swap(qr[0], qr[1]) @@ -215,8 +220,9 @@ def test_permute_wires_4(self): circuit.cx(qr[3], qr[0]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) expected = QuantumCircuit(qr) expected.h(qr[3]) @@ -254,8 +260,9 @@ def test_permute_wires_5(self): circuit.h(qr[3]) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) expected = QuantumCircuit(qr) expected.swap(qr[0], qr[1]) @@ -283,8 +290,9 @@ def test_all_single_qubit(self): circ.measure(qr[3], cr[3]) dag = circuit_to_dag(circ) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) self.assertEqual(dag, after) def test_overoptimization_case(self): @@ -363,8 +371,9 @@ def test_overoptimization_case(self): # qr[1]: 1, # qr[2]: 2, # qr[3]: 3} - pass_ = StochasticSwap(coupling, 20, 19) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 19) + after = pass_.run(dag) self.assertEqual(expected_dag, after) @@ -389,8 +398,9 @@ def test_already_mapped(self): dag = circuit_to_dag(circ) - pass_ = StochasticSwap(coupling, 20, 13) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 13) + after = pass_.run(dag) self.assertEqual(circuit_to_dag(circ), after) def test_congestion(self): @@ -465,8 +475,9 @@ def test_congestion(self): expected.measure(qr[1], cr[1]) expected_dag = circuit_to_dag(expected) - pass_ = StochasticSwap(coupling, 20, 999) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 999) + after = pass_.run(dag) self.assertEqual(expected_dag, after) def test_only_output_cx_and_swaps_in_coupling_map(self): @@ -483,8 +494,9 @@ def test_only_output_cx_and_swaps_in_coupling_map(self): circuit.measure(qr, cr) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling, 20, 5) - after = pass_.run(dag) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, 20, 5) + after = pass_.run(dag) valid_couplings = [{qr[a], qr[b]} for (a, b) in coupling.get_edges()] @@ -505,7 +517,8 @@ def test_len_cm_vs_dag(self): circuit.measure(qr, cr) dag = circuit_to_dag(circuit) - pass_ = StochasticSwap(coupling) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling) with self.assertRaises(TranspilerError): _ = pass_.run(dag) @@ -549,8 +562,9 @@ def test_single_gates_omitted(self): expected_dag = circuit_to_dag(expected) - stochastic = StochasticSwap(CouplingMap(coupling_map), seed=0) - after = PassManager(stochastic).run(circuit) + with self.assertWarns(DeprecationWarning): + stochastic = StochasticSwap(CouplingMap(coupling_map), seed=0) + after = PassManager(stochastic).run(circuit) after = circuit_to_dag(after) self.assertEqual(expected_dag, after) @@ -578,9 +592,10 @@ def test_pre_if_else_route(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=82).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=82).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -618,9 +633,10 @@ def test_pre_if_else_route_post_x(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=431).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=431).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -660,9 +676,10 @@ def test_post_if_else_route(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=6508).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=6508).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -700,9 +717,10 @@ def test_pre_if_else2(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=38).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=38).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -738,9 +756,10 @@ def test_intra_if_else_route(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=8).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=8).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -781,9 +800,10 @@ def test_pre_intra_if_else(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=2, trials=20).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=2, trials=20).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -829,9 +849,10 @@ def test_pre_intra_post_if_else(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=1).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=1).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -871,9 +892,10 @@ def test_if_expr(self): qc.if_test(expr.logic_and(qc.clbits[0], qc.clbits[1]), body, [0, 1, 2, 3], []) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=58).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=58).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) def test_if_else_expr(self): @@ -892,9 +914,10 @@ def test_if_else_expr(self): qc.if_else(expr.logic_and(qc.clbits[0], qc.clbits[1]), true, false, [0, 1, 2, 3], []) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=58).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=58).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) def test_standalone_vars(self): @@ -935,8 +958,9 @@ def test_standalone_vars(self): qc.cx(3, 1) cm = CouplingMap.from_line(5) - pm = PassManager([StochasticSwap(cm, seed=0), CheckMap(cm)]) - _ = pm.run(qc) + with self.assertWarns(DeprecationWarning): + pm = PassManager([StochasticSwap(cm, seed=0), CheckMap(cm)]) + _ = pm.run(qc) self.assertTrue(pm.property_set["is_swap_mapped"]) def test_no_layout_change(self): @@ -959,9 +983,10 @@ def test_no_layout_change(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=23).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=23).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -999,9 +1024,10 @@ def test_for_loop(self, nloops): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=687).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=687).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -1033,9 +1059,10 @@ def test_while_loop(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=58).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=58).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -1065,9 +1092,10 @@ def test_while_loop_expr(self): qc.while_loop(expr.logic_and(qc.clbits[0], qc.clbits[1]), body, [0, 1, 2, 3], []) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=58).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=58).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) def test_switch_single_case(self): @@ -1083,8 +1111,9 @@ def test_switch_single_case(self): qc.switch(creg, [(0, case0)], qreg[[0, 1, 2]], creg) coupling = CouplingMap.from_line(len(qreg)) - pass_ = StochasticSwap(coupling, seed=58) - test = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, seed=58) + test = pass_(qc) check = CheckMap(coupling) check(test) @@ -1122,8 +1151,9 @@ def test_switch_nonexhaustive(self): qc.switch(creg, [(0, case0), ((1, 2), case1), (3, case2)], qreg, creg) coupling = CouplingMap.from_line(len(qreg)) - pass_ = StochasticSwap(coupling, seed=58) - test = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, seed=58) + test = pass_(qc) check = CheckMap(coupling) check(test) @@ -1167,8 +1197,9 @@ def test_switch_exhaustive(self, labels): qc.switch(creg, [(labels, case0)], qreg[[0, 1, 2]], creg) coupling = CouplingMap.from_line(len(qreg)) - pass_ = StochasticSwap(coupling, seed=58) - test = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, seed=58) + test = pass_(qc) check = CheckMap(coupling) check(test) @@ -1205,8 +1236,9 @@ def test_switch_nonexhaustive_expr(self): qc.switch(expr.bit_or(creg, 5), [(0, case0), ((1, 2), case1), (3, case2)], qreg, creg) coupling = CouplingMap.from_line(len(qreg)) - pass_ = StochasticSwap(coupling, seed=58) - test = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, seed=58) + test = pass_(qc) check = CheckMap(coupling) check(test) @@ -1250,8 +1282,9 @@ def test_switch_exhaustive_expr(self, labels): qc.switch(expr.bit_or(creg, 3), [(labels, case0)], qreg[[0, 1, 2]], creg) coupling = CouplingMap.from_line(len(qreg)) - pass_ = StochasticSwap(coupling, seed=58) - test = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, seed=58) + test = pass_(qc) check = CheckMap(coupling) check(test) @@ -1295,9 +1328,10 @@ def test_nested_inner_cnot(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=seed).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=seed).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -1350,9 +1384,10 @@ def test_nested_outer_cnot(self): qc.measure(qreg, creg) dag = circuit_to_dag(qc) - cdag = StochasticSwap(coupling, seed=seed).run(dag) - check_map_pass = CheckMap(coupling) - check_map_pass.run(cdag) + with self.assertWarns(DeprecationWarning): + cdag = StochasticSwap(coupling, seed=seed).run(dag) + check_map_pass = CheckMap(coupling) + check_map_pass.run(cdag) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) expected = QuantumCircuit(qreg, creg) @@ -1386,7 +1421,8 @@ def test_disjoint_looping(self): loop_body = QuantumCircuit(2) loop_body.cx(0, 1) qc.for_loop((0,), None, loop_body, [0, 2], []) - cqc = StochasticSwap(cm, seed=0)(qc) + with self.assertWarns(DeprecationWarning): + cqc = StochasticSwap(cm, seed=0)(qc) expected = QuantumCircuit(qr) efor_body = QuantumCircuit(qr[[0, 1, 2]]) @@ -1408,7 +1444,8 @@ def test_disjoint_multiblock(self): false_body = QuantumCircuit(3, 1) false_body.cx(0, 2) qc.if_else((cr[0], 1), true_body, false_body, [0, 1, 2], [0]) - cqc = StochasticSwap(cm, seed=353)(qc) + with self.assertWarns(DeprecationWarning): + cqc = StochasticSwap(cm, seed=353)(qc) expected = QuantumCircuit(qr, cr) etrue_body = QuantumCircuit(qr[[0, 1, 2]], cr[[0]]) @@ -1431,7 +1468,8 @@ def test_multiple_ops_per_layer(self): qc.cx(0, 2) with qc.for_loop((0,)): qc.cx(3, 5) - cqc = StochasticSwap(coupling, seed=0)(qc) + with self.assertWarns(DeprecationWarning): + cqc = StochasticSwap(coupling, seed=0)(qc) check_map_pass(cqc) self.assertTrue(check_map_pass.property_set["is_swap_mapped"]) @@ -1465,8 +1503,9 @@ def test_if_no_else_restores_layout(self): qc.cx(2, 0) qc.cx(7, 6) coupling = CouplingMap.from_line(8) - pass_ = StochasticSwap(coupling, seed=2022_10_13) - transpiled = pass_(qc) + with self.assertWarns(DeprecationWarning): + pass_ = StochasticSwap(coupling, seed=2022_10_13) + transpiled = pass_(qc) # Check the pass claims to have done things right. initial_layout = Layout.generate_trivial_layout(*qc.qubits) @@ -1532,29 +1571,31 @@ def _visit_block(circuit, qubit_mapping=None): def test_random_circuit_no_control_flow(self, size): """Test that transpiled random circuits without control flow are physical circuits.""" circuit = random_circuit(size, 3, measure=True, seed=12342) - tqc = transpile( - circuit, - self.backend, - routing_method="stochastic", - layout_method="dense", - seed_transpiler=12342, - ) + with self.assertWarns(DeprecationWarning): + tqc = transpile( + circuit, + self.backend, + routing_method="stochastic", + layout_method="dense", + seed_transpiler=12342, + ) self.assert_valid_circuit(tqc) @data(*range(1, 27)) def test_random_circuit_no_control_flow_target(self, size): """Test that transpiled random circuits without control flow are physical circuits.""" circuit = random_circuit(size, 3, measure=True, seed=12342) - tqc = transpile( - circuit, - routing_method="stochastic", - layout_method="dense", - seed_transpiler=12342, - target=GenericBackendV2( - num_qubits=27, - coupling_map=MUMBAI_CMAP, - ).target, - ) + with self.assertWarns(DeprecationWarning): + tqc = transpile( + circuit, + routing_method="stochastic", + layout_method="dense", + seed_transpiler=12342, + target=GenericBackendV2( + num_qubits=27, + coupling_map=MUMBAI_CMAP, + ).target, + ) self.assert_valid_circuit(tqc) @data(*range(4, 27)) @@ -1569,14 +1610,15 @@ def test_random_circuit_for_loop(self, size): circuit.append(for_block, [1, 0, 2]) circuit.measure_all() - tqc = transpile( - circuit, - self.backend, - basis_gates=list(self.basis_gates), - routing_method="stochastic", - layout_method="dense", - seed_transpiler=12342, - ) + with self.assertWarns(DeprecationWarning): + tqc = transpile( + circuit, + self.backend, + basis_gates=list(self.basis_gates), + routing_method="stochastic", + layout_method="dense", + seed_transpiler=12342, + ) self.assert_valid_circuit(tqc) @data(*range(6, 27)) @@ -1598,14 +1640,15 @@ def test_random_circuit_if_else(self, size): with else_: circuit.append(else_block, [2, 5], clbit_indices[: else_block.num_clbits]) - tqc = transpile( - circuit, - self.backend, - basis_gates=list(self.basis_gates), - routing_method="stochastic", - layout_method="dense", - seed_transpiler=12342, - ) + with self.assertWarns(DeprecationWarning): + tqc = transpile( + circuit, + self.backend, + basis_gates=list(self.basis_gates), + routing_method="stochastic", + layout_method="dense", + seed_transpiler=12342, + ) self.assert_valid_circuit(tqc) From aa09a027bedeaa74f97771d1febc479d5d81d319 Mon Sep 17 00:00:00 2001 From: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:13:37 +0300 Subject: [PATCH 12/85] Fix Initialize.gates_to_uncompute method (#12976) * add back files needed in Initialize.gates_to_uncompute() * add a test for Initialize.gates_to_uncompute() method * fix a comment * add release notes * update gates_to_uncompute such that it will call Isometry * remove unused imports * transfer code from StatePreparation to Initialize.gates_to_uncompute * update code following review --- qiskit/circuit/library/data_preparation/initializer.py | 7 +++++-- .../circuit/library/data_preparation/state_preparation.py | 2 +- ...ix_initialize_gates_to_uncompute-d0dba6a642d07f30.yaml | 4 ++++ test/python/circuit/test_initializer.py | 8 ++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/fix_initialize_gates_to_uncompute-d0dba6a642d07f30.yaml diff --git a/qiskit/circuit/library/data_preparation/initializer.py b/qiskit/circuit/library/data_preparation/initializer.py index 0e38f067403c..984c7c0d310a 100644 --- a/qiskit/circuit/library/data_preparation/initializer.py +++ b/qiskit/circuit/library/data_preparation/initializer.py @@ -21,6 +21,7 @@ from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit.instruction import Instruction +from qiskit.circuit.library.generalized_gates import Isometry from .state_preparation import StatePreparation if typing.TYPE_CHECKING: @@ -86,9 +87,11 @@ def gates_to_uncompute(self) -> QuantumCircuit: """Call to create a circuit with gates that take the desired vector to zero. Returns: - Circuit to take ``self.params`` vector to :math:`|{00\\ldots0}\\rangle` + QuantumCircuit: circuit to take ``self.params`` vector to :math:`|{00\\ldots0}\\rangle` """ - return self._stateprep._gates_to_uncompute() + + isom = Isometry(self.params, 0, 0) + return isom._gates_to_uncompute() @property def params(self): diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index df69f9eab8c5..52006a8bb378 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -174,7 +174,7 @@ def _define_synthesis_isom(self): initialize_circuit = QuantumCircuit(q, name="init_def") isom = Isometry(self.params, 0, 0) - initialize_circuit.append(isom, q[:]) + initialize_circuit.compose(isom.definition, copy=False, inplace=True) # invert the circuit to create the desired vector from zero (assuming # the qubits are in the zero state) diff --git a/releasenotes/notes/fix_initialize_gates_to_uncompute-d0dba6a642d07f30.yaml b/releasenotes/notes/fix_initialize_gates_to_uncompute-d0dba6a642d07f30.yaml new file mode 100644 index 000000000000..3c24569455e2 --- /dev/null +++ b/releasenotes/notes/fix_initialize_gates_to_uncompute-d0dba6a642d07f30.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + Fix a bug that caused the method :meth:`Initialize.gates_to_uncompute()` fail. diff --git a/test/python/circuit/test_initializer.py b/test/python/circuit/test_initializer.py index a37c51f48184..2507fbc6c139 100644 --- a/test/python/circuit/test_initializer.py +++ b/test/python/circuit/test_initializer.py @@ -465,6 +465,14 @@ def test_mutating_params(self): self.assertEqual(decom_circ.data[2].operation.name, "state_preparation") self.assertEqual(decom_circ.data[2].operation.params, ["0", "0"]) + def test_gates_to_uncompute(self): + """Test the gates_to_uncompute() method.""" + desired_vector = [0.5, 0.5, 0.5, 0.5] + initialize = Initialize(desired_vector) + qc = initialize.gates_to_uncompute().inverse() + vec = Statevector(qc) + self.assertTrue(vec == Statevector(desired_vector)) + class TestInstructionParam(QiskitTestCase): """Test conversion of numpy type parameters.""" From b90c7a706f3848310fa1c0ddaaea5994b78ecfa4 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 20 Aug 2024 17:54:19 +0200 Subject: [PATCH 13/85] Tiny follow up to #12983 (#12999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * tiny follow up * Update releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- .../passes/routing/stochastic_swap.py | 4 +- ...ecate-StochasticSwap-451f46b273602b7b.yaml | 58 ++++++++++--------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/qiskit/transpiler/passes/routing/stochastic_swap.py b/qiskit/transpiler/passes/routing/stochastic_swap.py index 8cb628501017..a3ebbd6cbdde 100644 --- a/qiskit/transpiler/passes/routing/stochastic_swap.py +++ b/qiskit/transpiler/passes/routing/stochastic_swap.py @@ -63,8 +63,8 @@ class StochasticSwap(TransformationPass): @deprecate_func( since="1.3", removal_timeline="in the 2.0 release", - additional_msg="The `StochasticSwap` transpilation pass is a suboptimal " - "routing algorithm and has been superseded by the :class:`.SabreSwap` pass.", + additional_msg="The StochasticSwap transpilation pass is a suboptimal " + "routing algorithm and has been superseded by the SabreSwap pass.", ) def __init__(self, coupling_map, trials=20, seed=None, fake_run=False, initial_layout=None): """StochasticSwap initializer. diff --git a/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml b/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml index 24ade535f294..c858dd6fe6ab 100644 --- a/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml +++ b/releasenotes/notes/deprecate-StochasticSwap-451f46b273602b7b.yaml @@ -1,45 +1,49 @@ --- deprecations_transpiler: - | - Deprecated ``StochasticSwap`` which has been superseded by :class:`.SabreSwap`. + Deprecated :class:`.StochasticSwap` which has been superseded by :class:`.SabreSwap`. If the class is called from the transpile function, the change would be, for example:: + from qiskit import transpile + from qiskit.circuit import QuantumCircuit + from qiskit.transpiler import CouplingMap + from qiskit.providers.fake_provider import GenericBackendV2 + + + qc = QuantumCircuit(4) + qc.h(0) + qc.cx(0, range(1, 4)) + qc.measure_all() + + cmap = CouplingMap.from_heavy_hex(3) + backend = GenericBackendV2(num_qubits=cmap.size(), coupling_map=cmap) + tqc = transpile( - circuit, - routing_method="stochastic", - layout_method="dense", - seed_transpiler=12342, - target=GenericBackendV2( - num_qubits=27, - coupling_map=MUMBAI_CMAP, - ).target, - ) + qc, + routing_method="stochastic", + layout_method="dense", + seed_transpiler=12342, + target=backend.target + ) to:: tqc = transpile( - circuit, - routing_method="sabre", - layout_method="sabre", - seed_transpiler=12342, - target=GenericBackendV2( - num_qubits=27, - coupling_map=MUMBAI_CMAP, - ).target, - ) - - While for a pass mananager change:: - - qr = QuantumRegister(4, "q") - qc = QuantumCircuit(qr) + qc, + routing_method="sabre", + layout_method="sabre", + seed_transpiler=12342, + target=backend.target + ) + + While for a pass manager, the change would be:: + passmanager = PassManager(StochasticSwap(coupling, 20, 13)) new_qc = passmanager.run(qc) to:: - qr = QuantumRegister(5, "q") - qc = QuantumCircuit(qr) - passmanager = PassManager(SabreSwap(target, "basic")) + passmanager = PassManager(SabreSwap(backend.target, "basic")) new_qc = passmanager.run(qc) From 6107799ce19996ed125cb3f01663ad394e4eadbc Mon Sep 17 00:00:00 2001 From: Shravan Patel <78003234+shravanpatel30@users.noreply.github.com> Date: Wed, 21 Aug 2024 04:31:03 -0500 Subject: [PATCH 14/85] Extended the `from_backend` method of `InstructionDurations` to support both `BackendV1` and `BackendV2` (#12941) * Extended the `from_backend` method of `InstructionDurations` to support `GenericBackendV2` * Simplified the `from_backend` method to allow using `BackendV2`. Added a test and a releasenote. * Made changes to the releasenote. --- qiskit/transpiler/instruction_durations.py | 4 ++++ .../notes/fix-InstructionDurations-b47a9770b424d7a0.yaml | 5 +++++ test/python/transpiler/test_instruction_durations.py | 8 ++++++++ 3 files changed, 17 insertions(+) create mode 100644 releasenotes/notes/fix-InstructionDurations-b47a9770b424d7a0.yaml diff --git a/qiskit/transpiler/instruction_durations.py b/qiskit/transpiler/instruction_durations.py index 85d89bb16a18..56f8b5587c0c 100644 --- a/qiskit/transpiler/instruction_durations.py +++ b/qiskit/transpiler/instruction_durations.py @@ -18,6 +18,7 @@ from qiskit.circuit import Barrier, Delay, Instruction, ParameterExpression from qiskit.circuit.duration import duration_in_dt from qiskit.providers import Backend +from qiskit.providers.backend import BackendV2 from qiskit.transpiler.exceptions import TranspilerError from qiskit.utils.units import apply_prefix @@ -75,6 +76,9 @@ def from_backend(cls, backend: Backend): TranspilerError: If dt and dtm is different in the backend. """ # All durations in seconds in gate_length + if isinstance(backend, BackendV2): + return backend.target.durations() + instruction_durations = [] backend_properties = backend.properties() if hasattr(backend_properties, "_gates"): diff --git a/releasenotes/notes/fix-InstructionDurations-b47a9770b424d7a0.yaml b/releasenotes/notes/fix-InstructionDurations-b47a9770b424d7a0.yaml new file mode 100644 index 000000000000..ce8b789462de --- /dev/null +++ b/releasenotes/notes/fix-InstructionDurations-b47a9770b424d7a0.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed a bug where :meth:`.InstructionDurations.from_backend` did not work for :class:`.BackendV2` backends. + Fixed `#12760 `. \ No newline at end of file diff --git a/test/python/transpiler/test_instruction_durations.py b/test/python/transpiler/test_instruction_durations.py index de68fbadf86a..c59d0ff2a6cc 100644 --- a/test/python/transpiler/test_instruction_durations.py +++ b/test/python/transpiler/test_instruction_durations.py @@ -16,6 +16,7 @@ from qiskit.circuit import Delay, Parameter from qiskit.providers.fake_provider import Fake27QPulseV1 +from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.instruction_durations import InstructionDurations from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -92,3 +93,10 @@ def test_fail_if_get_unbounded_duration_with_unit_conversion_when_dt_is_not_prov parameterized_delay = Delay(param, "s") with self.assertRaises(TranspilerError): InstructionDurations().get(parameterized_delay, 0) + + def test_from_backend_with_backendv2(self): + """Test if `from_backend()` method allows using BackendV2""" + backend = GenericBackendV2(num_qubits=4, calibrate_instructions=True, seed=42) + inst_durations = InstructionDurations.from_backend(backend) + self.assertEqual(inst_durations, backend.target.durations()) + self.assertIsInstance(inst_durations, InstructionDurations) From 6f482400e56345fe260d2144bf86acfd563855bc Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 21 Aug 2024 17:35:29 +0200 Subject: [PATCH 15/85] qiskit.pulse.library.Square_fun.rst (#13007) --- qiskit/pulse/library/symbolic_pulses.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qiskit/pulse/library/symbolic_pulses.py b/qiskit/pulse/library/symbolic_pulses.py index 33d428771b22..b7ba658da1be 100644 --- a/qiskit/pulse/library/symbolic_pulses.py +++ b/qiskit/pulse/library/symbolic_pulses.py @@ -1773,12 +1773,13 @@ def Square( is the sign function with the convention :math:`\\text{sign}\\left(0\\right)=1`. Args: - duration: Pulse length in terms of the sampling period `dt`. - amp: The magnitude of the amplitude of the square wave. Wave range is [-`amp`,`amp`]. + duration: Pulse length in terms of the sampling period ``dt``. + amp: The magnitude of the amplitude of the square wave. Wave range is + :math:`\\left[-\\texttt{amp},\\texttt{amp}\\right]`. phase: The phase of the square wave (note that this is not equivalent to the angle of the complex amplitude). freq: The frequency of the square wave, in terms of 1 over sampling period. - If not provided defaults to a single cycle (i.e :math:'\\frac{1}{\\text{duration}}'). + If not provided defaults to a single cycle (i.e :math:`\\frac{1}{\\text{duration}}`). The frequency is limited to the range :math:`\\left(0,0.5\\right]` (the Nyquist frequency). angle: The angle in radians of the complex phase factor uniformly scaling the pulse. Default value 0. From fb81116adcbfda6314594462edcac547b0875717 Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Thu, 22 Aug 2024 10:53:50 +0300 Subject: [PATCH 16/85] Operator equality with (clean) ancillas (#12968) * initial commit * making the function private; also adding ignore_phase arg * applying review suggestions --- .../quantum_info/operators/operator_utils.py | 76 +++++++++++++++++++ .../quantum_info/operators/test_operator.py | 24 ++++++ 2 files changed, 100 insertions(+) create mode 100644 qiskit/quantum_info/operators/operator_utils.py diff --git a/qiskit/quantum_info/operators/operator_utils.py b/qiskit/quantum_info/operators/operator_utils.py new file mode 100644 index 000000000000..092252df951f --- /dev/null +++ b/qiskit/quantum_info/operators/operator_utils.py @@ -0,0 +1,76 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2024. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Additional utilities for Operators. +""" + +from __future__ import annotations + +from qiskit.quantum_info import Operator +from qiskit.quantum_info.operators.predicates import matrix_equal + + +def _equal_with_ancillas( + op1: Operator, + op2: Operator, + ancilla_qubits: list[int], + ignore_phase: bool = False, + rtol: float | None = None, + atol: float | None = None, +) -> bool: + r"""Test if two Operators are equal on the subspace where ancilla qubits + are :math:`|0\rangle`. + + Args: + op1 (Operator): an operator object. + op2 (Operator): an operator object. + ancilla_qubits (list[int]): a list of clean ancilla qubits. + ignore_phase (bool): ignore complex-phase difference between matrices. + rtol (float): relative tolerance value for comparison. + atol (float): absolute tolerance value for comparison. + + Returns: + bool: True iff operators are equal up to clean ancilla qubits. + """ + if op1.dim != op2.dim: + return False + + if atol is None: + atol = op1.atol + if rtol is None: + rtol = op1.rtol + + num_qubits = op1._op_shape._num_qargs_l + num_non_ancillas = num_qubits - len(ancilla_qubits) + + # Find a permutation that moves all ancilla qubits to the back + pattern = [] + ancillas = [] + for q in range(num_qubits): + if q not in ancilla_qubits: + pattern.append(q) + else: + ancillas.append(q) + pattern = pattern + ancillas + + # Apply this permutation to both operators + permuted1 = op1.apply_permutation(pattern) + permuted2 = op2.apply_permutation(pattern) + + # Restrict to the subspace where ancillas are 0 + restricted1 = permuted1.data[: 2**num_non_ancillas, : 2**num_qubits] + restricted2 = permuted2.data[: 2**num_non_ancillas, : 2**num_qubits] + + return matrix_equal( + restricted1, restricted2.data, ignore_phase=ignore_phase, rtol=rtol, atol=atol + ) diff --git a/test/python/quantum_info/operators/test_operator.py b/test/python/quantum_info/operators/test_operator.py index d653d6182017..725c46576a9d 100644 --- a/test/python/quantum_info/operators/test_operator.py +++ b/test/python/quantum_info/operators/test_operator.py @@ -31,6 +31,7 @@ from qiskit.transpiler.layout import Layout, TranspileLayout from qiskit.quantum_info.operators import Operator, ScalarOp from qiskit.quantum_info.operators.predicates import matrix_equal +from qiskit.quantum_info.operators.operator_utils import _equal_with_ancillas from qiskit.compiler.transpiler import transpile from qiskit.circuit import Qubit from qiskit.circuit.library import Permutation, PermutationGate @@ -1255,6 +1256,29 @@ def test_apply_permutation_dimensions(self): op2 = op.apply_permutation([2, 0, 1], front=True) self.assertEqual(op2.input_dims(), (4, 2, 3)) + def test_equality_with_ancillas(self): + """Check correctness of the equal_with_ancillas method.""" + + # The two circuits below are equal provided that qubit 1 is initially |0>. + qc1 = QuantumCircuit(4) + qc1.x(0) + qc1.x(2) + qc1.cx(1, 0) + qc1.cx(1, 2) + qc1.cx(1, 3) + op1 = Operator(qc1) + + qc2 = QuantumCircuit(4) + qc2.x(0) + qc2.x(2) + op2 = Operator(qc2) + + self.assertNotEqual(op1, op2) + self.assertFalse(_equal_with_ancillas(op1, op2, [])) + self.assertTrue(_equal_with_ancillas(op1, op2, [1])) + self.assertFalse(_equal_with_ancillas(op1, op2, [2])) + self.assertTrue(_equal_with_ancillas(op1, op2, [2, 1])) + if __name__ == "__main__": unittest.main() From 072548ff09cabfa8b9db8297926c5a609adde10b Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Thu, 22 Aug 2024 13:06:09 +0300 Subject: [PATCH 17/85] Adding MCX synthesis plugins (#12961) * moving high-level-synthesis plugins to a separate file * Adding the remaining MCX synthesis functions and exposting all of them as HLS synthesis plugins. * adding entry points for MCX plugins * adding documentation section for MCX plugins * renaming file * Adding pending deprecation warnings * placeholder for MCX plugin tests * adding flag pending=True to deprecate * changing checks from isinstance to name-based: a CCCX gate is called mcx but is not an MCXGate * futher exposing C3X and C4X synthesis * updating MCX synthesis functions to avoid returning C3X and C4X gates For better or for worse, C3X and C4X gates have name 'mcx', and therefore are caught by mcx plugins. We need to avoid recursion with HLS calling an MCX-synthesis plugin for a C3X-gate, which in turns returns a C3X-gate. * fix compose to append * renaming synthesized circuits for c3x and for c4x back to 'mcx' to avoid qasm changes * test qasm fixes * randomly spotted typo * fixing how QuantumCircuit.decompose works in the presence of gates_to_decompose * updating MCX plugins to check isinstance * fixing test * pylint fixes * properly fixing test * additional tests * adding new synthesis functions to synthesis docs * release notes * docstrings improvements followin review * Adding refernce to Vale et al paper for the MCXPhase gate implementation * fixes to deprecation warnings and adding deprecation for get_num_ancilla_qubits * docstring fixes * renaming mcphase to v24 * removing unncessary checks * addressing the rest of review comments * and of course updating qasm checking after we've slightly changed the decomposition * yet another renaming * Update qiskit/circuit/library/standard_gates/x.py Co-authored-by: Julien Gacon * Update qiskit/circuit/library/standard_gates/x.py Co-authored-by: Julien Gacon * Update releasenotes/notes/add-mcx-plugins-85e5b248692a36db.yaml Co-authored-by: Julien Gacon * release notes * formatting * fixing docs * removing references from the first sentence of plugin descriptions --------- Co-authored-by: Julien Gacon --- pyproject.toml | 40 +- qiskit/circuit/library/standard_gates/x.py | 77 +- qiskit/circuit/quantumcircuit.py | 9 +- qiskit/synthesis/__init__.py | 10 +- qiskit/synthesis/multi_controlled/__init__.py | 6 +- ...ith_ancillas_synth.py => mcx_synthesis.py} | 158 ++- .../passes/synthesis/high_level_synthesis.py | 594 +---------- .../passes/synthesis/hls_plugins.py | 928 ++++++++++++++++++ qiskit/transpiler/passes/synthesis/plugin.py | 2 +- .../add-mcx-plugins-85e5b248692a36db.yaml | 45 + test/python/circuit/test_circuit_qasm.py | 16 +- test/python/qasm2/test_export.py | 18 +- test/python/transpiler/test_decompose.py | 2 +- .../transpiler/test_high_level_synthesis.py | 174 +++- 14 files changed, 1400 insertions(+), 679 deletions(-) rename qiskit/synthesis/multi_controlled/{mcx_with_ancillas_synth.py => mcx_synthesis.py} (66%) create mode 100644 qiskit/transpiler/passes/synthesis/hls_plugins.py create mode 100644 releasenotes/notes/add-mcx-plugins-85e5b248692a36db.yaml diff --git a/pyproject.toml b/pyproject.toml index b1f7b039e407..9a16fc6e0ac3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,23 +75,29 @@ aqc = "qiskit.transpiler.passes.synthesis.aqc_plugin:AQCSynthesisPlugin" sk = "qiskit.transpiler.passes.synthesis.solovay_kitaev_synthesis:SolovayKitaevSynthesis" [project.entry-points."qiskit.synthesis"] -"clifford.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisClifford" -"clifford.ag" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:AGSynthesisClifford" -"clifford.bm" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BMSynthesisClifford" -"clifford.greedy" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:GreedySynthesisClifford" -"clifford.layers" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerSynthesisClifford" -"clifford.lnn" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerLnnSynthesisClifford" -"linear_function.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisLinearFunction" -"linear_function.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisLinearFunction" -"linear_function.pmh" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:PMHSynthesisLinearFunction" -"permutation.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation" -"permutation.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisPermutation" -"permutation.basic" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation" -"permutation.acg" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:ACGSynthesisPermutation" -"qft.full" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull" -"qft.line" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisLine" -"qft.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull" -"permutation.token_swapper" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:TokenSwapperSynthesisPermutation" +"clifford.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:DefaultSynthesisClifford" +"clifford.ag" = "qiskit.transpiler.passes.synthesis.hls_plugins:AGSynthesisClifford" +"clifford.bm" = "qiskit.transpiler.passes.synthesis.hls_plugins:BMSynthesisClifford" +"clifford.greedy" = "qiskit.transpiler.passes.synthesis.hls_plugins:GreedySynthesisClifford" +"clifford.layers" = "qiskit.transpiler.passes.synthesis.hls_plugins:LayerSynthesisClifford" +"clifford.lnn" = "qiskit.transpiler.passes.synthesis.hls_plugins:LayerLnnSynthesisClifford" +"linear_function.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:DefaultSynthesisLinearFunction" +"linear_function.kms" = "qiskit.transpiler.passes.synthesis.hls_plugins:KMSSynthesisLinearFunction" +"linear_function.pmh" = "qiskit.transpiler.passes.synthesis.hls_plugins:PMHSynthesisLinearFunction" +"mcx.n_dirty_i15" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisNDirtyI15" +"mcx.n_clean_m15" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisNCleanM15" +"mcx.1_clean_b95" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesis1CleanB95" +"mcx.gray_code" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisGrayCode" +"mcx.noaux_v24" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisNoAuxV24" +"mcx.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisDefault" +"permutation.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:BasicSynthesisPermutation" +"permutation.kms" = "qiskit.transpiler.passes.synthesis.hls_plugins:KMSSynthesisPermutation" +"permutation.basic" = "qiskit.transpiler.passes.synthesis.hls_plugins:BasicSynthesisPermutation" +"permutation.acg" = "qiskit.transpiler.passes.synthesis.hls_plugins:ACGSynthesisPermutation" +"qft.full" = "qiskit.transpiler.passes.synthesis.hls_plugins:QFTSynthesisFull" +"qft.line" = "qiskit.transpiler.passes.synthesis.hls_plugins:QFTSynthesisLine" +"qft.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:QFTSynthesisFull" +"permutation.token_swapper" = "qiskit.transpiler.passes.synthesis.hls_plugins:TokenSwapperSynthesisPermutation" [project.entry-points."qiskit.transpiler.init"] default = "qiskit.transpiler.preset_passmanagers.builtin_plugins:DefaultInitPassManager" diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 3ee5551b599d..f24c76c65d91 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -20,6 +20,7 @@ from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit._utils import _ctrl_state_to_int, with_gate_array, with_controlled_gate_array from qiskit._accelerate.circuit import StandardGate +from qiskit.utils.deprecation import deprecate_func _X_ARRAY = [[0, 1], [1, 0]] _SX_ARRAY = [[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]] @@ -1168,6 +1169,19 @@ def inverse(self, annotated: bool = False): return MCXGate(num_ctrl_qubits=self.num_ctrl_qubits, ctrl_state=self.ctrl_state) @staticmethod + @deprecate_func( + additional_msg=( + "For an MCXGate it is no longer possible to know the number of ancilla qubits " + "that would be eventually used by the transpiler when the gate is created. " + "Instead, it is recommended to use MCXGate and let HighLevelSynthesis choose " + "the best synthesis method depending on the number of ancilla qubits available. " + "However, if a specific synthesis method using a specific number of ancilla " + "qubits is require, one can create a custom gate by calling the corresponding " + "synthesis function directly." + ), + since="1.3", + pending=True, + ) def get_num_ancilla_qubits(num_ctrl_qubits: int, mode: str = "noancilla") -> int: """Get the number of required ancilla qubits without instantiating the class. @@ -1185,23 +1199,10 @@ def get_num_ancilla_qubits(num_ctrl_qubits: int, mode: str = "noancilla") -> int def _define(self): """This definition is based on MCPhaseGate implementation.""" # pylint: disable=cyclic-import - from qiskit.circuit.quantumcircuit import QuantumCircuit + from qiskit.synthesis.multi_controlled import synth_mcx_noaux_v24 - q = QuantumRegister(self.num_qubits, name="q") - qc = QuantumCircuit(q) - if self.num_qubits == 4: - qc._append(C3XGate(), q[:], []) - self.definition = qc - elif self.num_qubits == 5: - qc._append(C4XGate(), q[:], []) - self.definition = qc - else: - q_controls = list(range(self.num_ctrl_qubits)) - q_target = self.num_ctrl_qubits - qc.h(q_target) - qc.mcp(numpy.pi, q_controls, q_target) - qc.h(q_target) - self.definition = qc + qc = synth_mcx_noaux_v24(self.num_ctrl_qubits) + self.definition = qc @property def num_ancilla_qubits(self): @@ -1280,6 +1281,17 @@ def __new__( return gate return super().__new__(cls) + @deprecate_func( + additional_msg=( + "It is recommended to use MCXGate and let HighLevelSynthesis choose " + "the best synthesis method depending on the number of ancilla qubits available. " + "If this specific synthesis method is required, one can specify it using the " + "high-level-synthesis plugin `gray_code` for MCX gates, or, alternatively, " + "one can use synth_mcx_gray_code to construct the gate directly." + ), + since="1.3", + pending=True, + ) def __init__( self, num_ctrl_qubits: int, @@ -1305,15 +1317,9 @@ def inverse(self, annotated: bool = False): def _define(self): """Define the MCX gate using the Gray code.""" # pylint: disable=cyclic-import - from qiskit.circuit.quantumcircuit import QuantumCircuit - from .u1 import MCU1Gate - from .h import HGate + from qiskit.synthesis.multi_controlled import synth_mcx_gray_code - q = QuantumRegister(self.num_qubits, name="q") - qc = QuantumCircuit(q, name=self.name) - qc._append(HGate(), [q[-1]], []) - qc._append(MCU1Gate(numpy.pi, num_ctrl_qubits=self.num_ctrl_qubits), q[:], []) - qc._append(HGate(), [q[-1]], []) + qc = synth_mcx_gray_code(self.num_ctrl_qubits) self.definition = qc @@ -1330,6 +1336,17 @@ class MCXRecursive(MCXGate): 2. Iten et al., 2015. https://arxiv.org/abs/1501.06911 """ + @deprecate_func( + additional_msg=( + "It is recommended to use MCXGate and let HighLevelSynthesis choose " + "the best synthesis method depending on the number of ancilla qubits available. " + "If this specific synthesis method is required, one can specify it using the " + "high-level-synthesis plugin '1_clean_b95' for MCX gates, or, alternatively, " + "one can use synth_mcx_1_clean to construct the gate directly." + ), + since="1.3", + pending=True, + ) def __init__( self, num_ctrl_qubits: int, @@ -1409,6 +1426,18 @@ def __new__( unit=unit, ) + @deprecate_func( + additional_msg=( + "It is recommended to use MCXGate and let HighLevelSynthesis choose " + "the best synthesis method depending on the number of ancilla qubits available. " + "If this specific synthesis method is required, one can specify it using the " + "high-level-synthesis plugins `n_clean_m15` (using clean ancillas) or " + "`n_dirty_i15` (using dirty ancillas) for MCX gates. Alternatively, one can " + "use synth_mcx_n_dirty_i15 and synth_mcx_n_clean_m15 to construct the gate directly." + ), + since="1.3", + pending=True, + ) def __init__( self, num_ctrl_qubits: int, diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 9413141fb757..487f1e28e382 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -3212,10 +3212,17 @@ def decompose( from qiskit.converters.dag_to_circuit import dag_to_circuit dag = circuit_to_dag(self, copy_operations=True) - dag = HighLevelSynthesis().run(dag) + + if gates_to_decompose is None: + # We should not rewrite the circuit using HLS when we have gates_to_decompose, + # or else HLS will rewrite all objects with available plugins (e.g., Cliffords, + # PermutationGates, and now also MCXGates) + dag = HighLevelSynthesis().run(dag) + pass_ = Decompose(gates_to_decompose) for _ in range(reps): dag = pass_.run(dag) + # do not copy operations, this is done in the conversion with circuit_to_dag return dag_to_circuit(dag, copy_operations=False) diff --git a/qiskit/synthesis/__init__.py b/qiskit/synthesis/__init__.py index f1d1e3b28359..b2a92ee7caf5 100644 --- a/qiskit/synthesis/__init__.py +++ b/qiskit/synthesis/__init__.py @@ -128,6 +128,10 @@ .. autofunction:: synth_mcx_n_dirty_i15 .. autofunction:: synth_mcx_n_clean_m15 .. autofunction:: synth_mcx_1_clean_b95 +.. autofunction:: synth_mcx_noaux_v24 +.. autofunction:: synth_mcx_gray_code +.. autofunction:: synth_c3x +.. autofunction:: synth_c4x """ @@ -180,8 +184,12 @@ two_qubit_cnot_decompose, TwoQubitWeylDecomposition, ) -from .multi_controlled.mcx_with_ancillas_synth import ( +from .multi_controlled import ( synth_mcx_n_dirty_i15, synth_mcx_n_clean_m15, synth_mcx_1_clean_b95, + synth_mcx_noaux_v24, + synth_mcx_gray_code, + synth_c3x, + synth_c4x, ) diff --git a/qiskit/synthesis/multi_controlled/__init__.py b/qiskit/synthesis/multi_controlled/__init__.py index 0c04823a537a..84ec17c355e4 100644 --- a/qiskit/synthesis/multi_controlled/__init__.py +++ b/qiskit/synthesis/multi_controlled/__init__.py @@ -12,8 +12,12 @@ """Module containing multi-controlled circuits synthesis""" -from .mcx_with_ancillas_synth import ( +from .mcx_synthesis import ( synth_mcx_n_dirty_i15, synth_mcx_n_clean_m15, synth_mcx_1_clean_b95, + synth_mcx_gray_code, + synth_mcx_noaux_v24, + synth_c3x, + synth_c4x, ) diff --git a/qiskit/synthesis/multi_controlled/mcx_with_ancillas_synth.py b/qiskit/synthesis/multi_controlled/mcx_synthesis.py similarity index 66% rename from qiskit/synthesis/multi_controlled/mcx_with_ancillas_synth.py rename to qiskit/synthesis/multi_controlled/mcx_synthesis.py index cf2325764569..10680f0fee88 100644 --- a/qiskit/synthesis/multi_controlled/mcx_with_ancillas_synth.py +++ b/qiskit/synthesis/multi_controlled/mcx_synthesis.py @@ -10,20 +10,28 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Module containing multi-controlled circuits synthesis with ancillary qubits.""" +"""Module containing multi-controlled circuits synthesis with and without ancillary qubits.""" from math import ceil +import numpy as np + from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.circuit.library.standard_gates.x import C3XGate, C4XGate +from qiskit.circuit.library.standard_gates import ( + HGate, + MCU1Gate, + CU1Gate, + RC3XGate, + C3SXGate, +) def synth_mcx_n_dirty_i15( num_ctrl_qubits: int, relative_phase: bool = False, action_only: bool = False, -): - """ +) -> QuantumCircuit: + r""" Synthesize a multi-controlled X gate with :math:`k` controls using :math:`k - 2` dirty ancillary qubits producing a circuit with :math:`2 * k - 1` qubits and at most :math:`8 * k - 6` CX gates, by Iten et. al. [1]. @@ -59,7 +67,8 @@ def synth_mcx_n_dirty_i15( qc.ccx(q_controls[0], q_controls[1], q_target) return qc elif not relative_phase and num_ctrl_qubits == 3: - qc._append(C3XGate(), [*q_controls, q_target], []) + circuit = synth_c3x() + qc.compose(circuit, [*q_controls, q_target], inplace=True, copy=False) return qc num_ancillas = num_ctrl_qubits - 2 @@ -122,8 +131,8 @@ def synth_mcx_n_dirty_i15( return qc -def synth_mcx_n_clean_m15(num_ctrl_qubits: int): - """ +def synth_mcx_n_clean_m15(num_ctrl_qubits: int) -> QuantumCircuit: + r""" Synthesize a multi-controlled X gate with :math:`k` controls using :math:`k - 2` clean ancillary qubits with producing a circuit with :math:`2 * k - 1` qubits and at most :math:`6 * k - 6` CX gates, by Maslov [1]. @@ -165,8 +174,8 @@ def synth_mcx_n_clean_m15(num_ctrl_qubits: int): return qc -def synth_mcx_1_clean_b95(num_ctrl_qubits: int): - """ +def synth_mcx_1_clean_b95(num_ctrl_qubits: int) -> QuantumCircuit: + r""" Synthesize a multi-controlled X gate with :math:`k` controls using a single clean ancillary qubit producing a circuit with :math:`k + 2` qubits and at most :math:`16 * k - 8` CX gates, by Barenco et al. [1]. @@ -183,16 +192,10 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int): """ if num_ctrl_qubits == 3: - q = QuantumRegister(4, name="q") - qc = QuantumCircuit(q, name="mcx") - qc._append(C3XGate(), q[:], []) - return qc + return synth_c3x() elif num_ctrl_qubits == 4: - q = QuantumRegister(5, name="q") - qc = QuantumCircuit(q, name="mcx") - qc._append(C4XGate(), q[:], []) - return qc + return synth_c4x() num_qubits = num_ctrl_qubits + 2 q = QuantumRegister(num_qubits, name="q") @@ -230,3 +233,124 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int): ) return qc + + +def synth_mcx_gray_code(num_ctrl_qubits: int) -> QuantumCircuit: + r""" + Synthesize a multi-controlled X gate with :math:`k` controls using the Gray code. + + Produces a quantum circuit with :math:`k + 1` qubits. This method + produces exponentially many CX gates and should be used only for small + values of :math:`k`. + + Args: + num_ctrl_qubits: The number of control qubits. + + Returns: + The synthesized quantum circuit. + """ + num_qubits = num_ctrl_qubits + 1 + q = QuantumRegister(num_qubits, name="q") + qc = QuantumCircuit(q, name="mcx_gray") + qc._append(HGate(), [q[-1]], []) + qc._append(MCU1Gate(np.pi, num_ctrl_qubits=num_ctrl_qubits), q[:], []) + qc._append(HGate(), [q[-1]], []) + return qc + + +def synth_mcx_noaux_v24(num_ctrl_qubits: int) -> QuantumCircuit: + r""" + Synthesize a multi-controlled X gate with :math:`k` controls based on + the implementation for MCPhaseGate. + + In turn, the MCPhase gate uses the decomposition for multi-controlled + special unitaries described in [1]. + + Produces a quantum circuit with :math:`k + 1` qubits. + The number of CX-gates is quadratic in :math:`k`. + + Args: + num_ctrl_qubits: The number of control qubits. + + Returns: + The synthesized quantum circuit. + + References: + 1. Vale et. al., *Circuit Decomposition of Multicontrolled Special Unitary + Single-Qubit Gates*, IEEE TCAD 43(3) (2024), + `arXiv:2302.06377 `_ + """ + if num_ctrl_qubits == 3: + return synth_c3x() + + if num_ctrl_qubits == 4: + return synth_c4x() + + num_qubits = num_ctrl_qubits + 1 + q = QuantumRegister(num_qubits, name="q") + qc = QuantumCircuit(q) + q_controls = list(range(num_ctrl_qubits)) + q_target = num_ctrl_qubits + qc.h(q_target) + qc.mcp(np.pi, q_controls, q_target) + qc.h(q_target) + return qc + + +def synth_c3x() -> QuantumCircuit: + """Efficient synthesis of 3-controlled X-gate.""" + + q = QuantumRegister(4, name="q") + qc = QuantumCircuit(q, name="mcx") + qc.h(3) + qc.p(np.pi / 8, [0, 1, 2, 3]) + qc.cx(0, 1) + qc.p(-np.pi / 8, 1) + qc.cx(0, 1) + qc.cx(1, 2) + qc.p(-np.pi / 8, 2) + qc.cx(0, 2) + qc.p(np.pi / 8, 2) + qc.cx(1, 2) + qc.p(-np.pi / 8, 2) + qc.cx(0, 2) + qc.cx(2, 3) + qc.p(-np.pi / 8, 3) + qc.cx(1, 3) + qc.p(np.pi / 8, 3) + qc.cx(2, 3) + qc.p(-np.pi / 8, 3) + qc.cx(0, 3) + qc.p(np.pi / 8, 3) + qc.cx(2, 3) + qc.p(-np.pi / 8, 3) + qc.cx(1, 3) + qc.p(np.pi / 8, 3) + qc.cx(2, 3) + qc.p(-np.pi / 8, 3) + qc.cx(0, 3) + qc.h(3) + return qc + + +def synth_c4x() -> QuantumCircuit: + """Efficient synthesis of 4-controlled X-gate.""" + + q = QuantumRegister(5, name="q") + qc = QuantumCircuit(q, name="mcx") + + rules = [ + (HGate(), [q[4]], []), + (CU1Gate(np.pi / 2), [q[3], q[4]], []), + (HGate(), [q[4]], []), + (RC3XGate(), [q[0], q[1], q[2], q[3]], []), + (HGate(), [q[4]], []), + (CU1Gate(-np.pi / 2), [q[3], q[4]], []), + (HGate(), [q[4]], []), + (RC3XGate().inverse(), [q[0], q[1], q[2], q[3]], []), + (C3SXGate(), [q[0], q[1], q[2], q[4]], []), + ] + for instr, qargs, cargs in rules: + qc._append(instr, qargs, cargs) + + return qc diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index 247898182cba..38c46547b12d 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -10,153 +10,8 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. - """ - -High Level Synthesis Plugins ------------------------------ - -Clifford Synthesis -'''''''''''''''''' - -.. list-table:: Plugins for :class:`qiskit.quantum_info.Clifford` (key = ``"clifford"``) - :header-rows: 1 - - * - Plugin name - - Plugin class - - Targeted connectivity - - Description - * - ``"ag"`` - - :class:`~.AGSynthesisClifford` - - all-to-all - - greedily optimizes CX-count - * - ``"bm"`` - - :class:`~.BMSynthesisClifford` - - all-to-all - - optimal count for `n=2,3`; used in ``"default"`` for `n=2,3` - * - ``"greedy"`` - - :class:`~.GreedySynthesisClifford` - - all-to-all - - greedily optimizes CX-count; used in ``"default"`` for `n>=4` - * - ``"layers"`` - - :class:`~.LayerSynthesisClifford` - - all-to-all - - - * - ``"lnn"`` - - :class:`~.LayerLnnSynthesisClifford` - - linear - - many CX-gates but guarantees CX-depth of at most `7*n+2` - * - ``"default"`` - - :class:`~.DefaultSynthesisClifford` - - all-to-all - - usually best for optimizing CX-count (and optimal CX-count for `n=2,3`) - -.. autosummary:: - :toctree: ../stubs/ - - AGSynthesisClifford - BMSynthesisClifford - GreedySynthesisClifford - LayerSynthesisClifford - LayerLnnSynthesisClifford - DefaultSynthesisClifford - - -Linear Function Synthesis -''''''''''''''''''''''''' - -.. list-table:: Plugins for :class:`.LinearFunction` (key = ``"linear"``) - :header-rows: 1 - - * - Plugin name - - Plugin class - - Targeted connectivity - - Description - * - ``"kms"`` - - :class:`~.KMSSynthesisLinearFunction` - - linear - - many CX-gates but guarantees CX-depth of at most `5*n` - * - ``"pmh"`` - - :class:`~.PMHSynthesisLinearFunction` - - all-to-all - - greedily optimizes CX-count; used in ``"default"`` - * - ``"default"`` - - :class:`~.DefaultSynthesisLinearFunction` - - all-to-all - - best for optimizing CX-count - -.. autosummary:: - :toctree: ../stubs/ - - KMSSynthesisLinearFunction - PMHSynthesisLinearFunction - DefaultSynthesisLinearFunction - - -Permutation Synthesis -''''''''''''''''''''' - -.. list-table:: Plugins for :class:`.PermutationGate` (key = ``"permutation"``) - :header-rows: 1 - - * - Plugin name - - Plugin class - - Targeted connectivity - - Description - * - ``"basic"`` - - :class:`~.BasicSynthesisPermutation` - - all-to-all - - optimal SWAP-count; used in ``"default"`` - * - ``"acg"`` - - :class:`~.ACGSynthesisPermutation` - - all-to-all - - guarantees SWAP-depth of at most `2` - * - ``"kms"`` - - :class:`~.KMSSynthesisPermutation` - - linear - - many SWAP-gates, but guarantees SWAP-depth of at most `n` - * - ``"token_swapper"`` - - :class:`~.TokenSwapperSynthesisPermutation` - - any - - greedily optimizes SWAP-count for arbitrary connectivity - * - ``"default"`` - - :class:`~.BasicSynthesisPermutation` - - all-to-all - - best for optimizing SWAP-count - -.. autosummary:: - :toctree: ../stubs/ - - BasicSynthesisPermutation - ACGSynthesisPermutation - KMSSynthesisPermutation - TokenSwapperSynthesisPermutation - - -QFT Synthesis -''''''''''''' - -.. list-table:: Plugins for :class:`.QFTGate` (key = ``"qft"``) - :header-rows: 1 - - * - Plugin name - - Plugin class - - Targeted connectivity - * - ``"full"`` - - :class:`~.QFTSynthesisFull` - - all-to-all - * - ``"line"`` - - :class:`~.QFTSynthesisLine` - - linear - * - ``"default"`` - - :class:`~.QFTSynthesisFull` - - all-to-all - -.. autosummary:: - :toctree: ../stubs/ - - QFTSynthesisFull - QFTSynthesisLine +High-level-synthesis transpiler pass. """ from __future__ import annotations @@ -166,7 +21,6 @@ from collections.abc import Callable import numpy as np -import rustworkx as rx from qiskit.circuit.annotated_operation import Modifier from qiskit.circuit.operation import Operation @@ -175,13 +29,11 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.circuit import ControlledGate, EquivalenceLibrary, equivalence -from qiskit.circuit.library import LinearFunction from qiskit.transpiler.passes.utils import control_flow from qiskit.transpiler.target import Target from qiskit.transpiler.coupling import CouplingMap from qiskit.dagcircuit.dagcircuit import DAGCircuit from qiskit.transpiler.exceptions import TranspilerError -from qiskit.transpiler.passes.routing.algorithms import ApproximateTokenSwapper from qiskit.circuit.annotated_operation import ( AnnotatedOperation, @@ -189,32 +41,8 @@ ControlModifier, PowerModifier, ) -from qiskit.circuit.library import QFTGate -from qiskit.synthesis.clifford import ( - synth_clifford_full, - synth_clifford_layers, - synth_clifford_depth_lnn, - synth_clifford_greedy, - synth_clifford_ag, - synth_clifford_bm, -) -from qiskit.synthesis.linear import ( - synth_cnot_count_full_pmh, - synth_cnot_depth_line_kms, - calc_inverse_matrix, -) -from qiskit.synthesis.linear.linear_circuits_utils import transpose_cx_circ -from qiskit.synthesis.permutation import ( - synth_permutation_basic, - synth_permutation_acg, - synth_permutation_depth_lnn_kms, -) -from qiskit.synthesis.qft import ( - synth_qft_full, - synth_qft_line, -) -from .plugin import HighLevelSynthesisPluginManager, HighLevelSynthesisPlugin +from .plugin import HighLevelSynthesisPluginManager from .qubit_tracker import QubitTracker if typing.TYPE_CHECKING: @@ -838,424 +666,6 @@ def _instruction_supported(self, name: str, qubits: tuple[int] | None) -> bool: return self._target.instruction_supported(operation_name=name, qargs=qubits) -class DefaultSynthesisClifford(HighLevelSynthesisPlugin): - """The default clifford synthesis plugin. - - For N <= 3 qubits this is the optimal CX cost decomposition by Bravyi, Maslov. - For N > 3 qubits this is done using the general non-optimal greedy compilation - routine from reference by Bravyi, Hu, Maslov, Shaydulin. - - This plugin name is :``clifford.default`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Clifford.""" - decomposition = synth_clifford_full(high_level_object) - return decomposition - - -class AGSynthesisClifford(HighLevelSynthesisPlugin): - """Clifford synthesis plugin based on the Aaronson-Gottesman method. - - This plugin name is :``clifford.ag`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Clifford.""" - decomposition = synth_clifford_ag(high_level_object) - return decomposition - - -class BMSynthesisClifford(HighLevelSynthesisPlugin): - """Clifford synthesis plugin based on the Bravyi-Maslov method. - - The method only works on Cliffords with at most 3 qubits, for which it - constructs the optimal CX cost decomposition. - - This plugin name is :``clifford.bm`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Clifford.""" - if high_level_object.num_qubits <= 3: - decomposition = synth_clifford_bm(high_level_object) - else: - decomposition = None - return decomposition - - -class GreedySynthesisClifford(HighLevelSynthesisPlugin): - """Clifford synthesis plugin based on the greedy synthesis - Bravyi-Hu-Maslov-Shaydulin method. - - This plugin name is :``clifford.greedy`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Clifford.""" - decomposition = synth_clifford_greedy(high_level_object) - return decomposition - - -class LayerSynthesisClifford(HighLevelSynthesisPlugin): - """Clifford synthesis plugin based on the Bravyi-Maslov method - to synthesize Cliffords into layers. - - This plugin name is :``clifford.layers`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Clifford.""" - decomposition = synth_clifford_layers(high_level_object) - return decomposition - - -class LayerLnnSynthesisClifford(HighLevelSynthesisPlugin): - """Clifford synthesis plugin based on the Bravyi-Maslov method - to synthesize Cliffords into layers, with each layer synthesized - adhering to LNN connectivity. - - This plugin name is :``clifford.lnn`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Clifford.""" - decomposition = synth_clifford_depth_lnn(high_level_object) - return decomposition - - -class DefaultSynthesisLinearFunction(HighLevelSynthesisPlugin): - """The default linear function synthesis plugin. - - This plugin name is :``linear_function.default`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given LinearFunction.""" - decomposition = synth_cnot_count_full_pmh(high_level_object.linear) - return decomposition - - -class KMSSynthesisLinearFunction(HighLevelSynthesisPlugin): - """Linear function synthesis plugin based on the Kutin-Moulton-Smithline method. - - This plugin name is :``linear_function.kms`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - - The plugin supports the following plugin-specific options: - - * use_inverted: Indicates whether to run the algorithm on the inverse matrix - and to invert the synthesized circuit. - In certain cases this provides a better decomposition than the direct approach. - * use_transposed: Indicates whether to run the algorithm on the transposed matrix - and to invert the order of CX gates in the synthesized circuit. - In certain cases this provides a better decomposition than the direct approach. - - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given LinearFunction.""" - - if not isinstance(high_level_object, LinearFunction): - raise TranspilerError( - "PMHSynthesisLinearFunction only accepts objects of type LinearFunction" - ) - - use_inverted = options.get("use_inverted", False) - use_transposed = options.get("use_transposed", False) - - mat = high_level_object.linear.astype(bool, copy=False) - - if use_transposed: - mat = np.transpose(mat) - if use_inverted: - mat = calc_inverse_matrix(mat) - - decomposition = synth_cnot_depth_line_kms(mat) - - if use_transposed: - decomposition = transpose_cx_circ(decomposition) - if use_inverted: - decomposition = decomposition.inverse() - - return decomposition - - -class PMHSynthesisLinearFunction(HighLevelSynthesisPlugin): - """Linear function synthesis plugin based on the Patel-Markov-Hayes method. - - This plugin name is :``linear_function.pmh`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - - The plugin supports the following plugin-specific options: - - * section size: The size of each section used in the Patel–Markov–Hayes algorithm [1]. - * use_inverted: Indicates whether to run the algorithm on the inverse matrix - and to invert the synthesized circuit. - In certain cases this provides a better decomposition than the direct approach. - * use_transposed: Indicates whether to run the algorithm on the transposed matrix - and to invert the order of CX gates in the synthesized circuit. - In certain cases this provides a better decomposition than the direct approach. - - References: - 1. Patel, Ketan N., Igor L. Markov, and John P. Hayes, - *Optimal synthesis of linear reversible circuits*, - Quantum Information & Computation 8.3 (2008): 282-294. - `arXiv:quant-ph/0302002 [quant-ph] `_ - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given LinearFunction.""" - - if not isinstance(high_level_object, LinearFunction): - raise TranspilerError( - "PMHSynthesisLinearFunction only accepts objects of type LinearFunction" - ) - - section_size = options.get("section_size", 2) - use_inverted = options.get("use_inverted", False) - use_transposed = options.get("use_transposed", False) - - mat = high_level_object.linear.astype(bool, copy=False) - - if use_transposed: - mat = np.transpose(mat) - if use_inverted: - mat = calc_inverse_matrix(mat) - - decomposition = synth_cnot_count_full_pmh(mat, section_size=section_size) - - if use_transposed: - decomposition = transpose_cx_circ(decomposition) - if use_inverted: - decomposition = decomposition.inverse() - - return decomposition - - -class KMSSynthesisPermutation(HighLevelSynthesisPlugin): - """The permutation synthesis plugin based on the Kutin, Moulton, Smithline method. - - This plugin name is :``permutation.kms`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Permutation.""" - decomposition = synth_permutation_depth_lnn_kms(high_level_object.pattern) - return decomposition - - -class BasicSynthesisPermutation(HighLevelSynthesisPlugin): - """The permutation synthesis plugin based on sorting. - - This plugin name is :``permutation.basic`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Permutation.""" - decomposition = synth_permutation_basic(high_level_object.pattern) - return decomposition - - -class ACGSynthesisPermutation(HighLevelSynthesisPlugin): - """The permutation synthesis plugin based on the Alon, Chung, Graham method. - - This plugin name is :``permutation.acg`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Permutation.""" - decomposition = synth_permutation_acg(high_level_object.pattern) - return decomposition - - -class QFTSynthesisFull(HighLevelSynthesisPlugin): - """Synthesis plugin for QFT gates using all-to-all connectivity. - - This plugin name is :``qft.full`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - - The plugin supports the following additional options: - - * reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``, - which is the default) or the "QFT-with-reversal" operation (if ``True``). - Some implementation of the ``QFTGate`` include a layer of swap gates at the end - of the synthesized circuit, which can in principle be dropped if the ``QFTGate`` - itself is the last gate in the circuit. - * approximation_degree (int): The degree of approximation (0 for no approximation). - It is possible to implement the QFT approximately by ignoring - controlled-phase rotations with the angle beneath a threshold. This is discussed - in more detail in [1] or [2]. - * insert_barriers (bool): If True, barriers are inserted as visualization improvement. - * inverse (bool): If True, the inverse Fourier transform is constructed. - * name (str): The name of the circuit. - - References: - 1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä, - *Approximate Quantum Fourier Transform and Decoherence*, - Physical Review A (1996). - `arXiv:quant-ph/9601018 [quant-ph] `_ - 2. Donny Cheung, - *Improved Bounds for the Approximate QFT* (2004), - `arXiv:quant-ph/0403071 [quant-ph] `_ - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given QFTGate.""" - if not isinstance(high_level_object, QFTGate): - raise TranspilerError( - "The synthesis plugin 'qft.full` only applies to objects of type QFTGate." - ) - - reverse_qubits = options.get("reverse_qubits", False) - approximation_degree = options.get("approximation_degree", 0) - insert_barriers = options.get("insert_barriers", False) - inverse = options.get("inverse", False) - name = options.get("name", None) - - decomposition = synth_qft_full( - num_qubits=high_level_object.num_qubits, - do_swaps=not reverse_qubits, - approximation_degree=approximation_degree, - insert_barriers=insert_barriers, - inverse=inverse, - name=name, - ) - return decomposition - - -class QFTSynthesisLine(HighLevelSynthesisPlugin): - """Synthesis plugin for QFT gates using linear connectivity. - - This plugin name is :``qft.line`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - - The plugin supports the following additional options: - - * reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``, - which is the default) or the "QFT-with-reversal" operation (if ``True``). - Some implementation of the ``QFTGate`` include a layer of swap gates at the end - of the synthesized circuit, which can in principle be dropped if the ``QFTGate`` - itself is the last gate in the circuit. - * approximation_degree (int): the degree of approximation (0 for no approximation). - It is possible to implement the QFT approximately by ignoring - controlled-phase rotations with the angle beneath a threshold. This is discussed - in more detail in [1] or [2]. - - References: - 1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä, - *Approximate Quantum Fourier Transform and Decoherence*, - Physical Review A (1996). - `arXiv:quant-ph/9601018 [quant-ph] `_ - 2. Donny Cheung, - *Improved Bounds for the Approximate QFT* (2004), - `arXiv:quant-ph/0403071 [quant-ph] `_ - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given QFTGate.""" - if not isinstance(high_level_object, QFTGate): - raise TranspilerError( - "The synthesis plugin 'qft.line` only applies to objects of type QFTGate." - ) - - reverse_qubits = options.get("reverse_qubits", False) - approximation_degree = options.get("approximation_degree", 0) - - decomposition = synth_qft_line( - num_qubits=high_level_object.num_qubits, - do_swaps=not reverse_qubits, - approximation_degree=approximation_degree, - ) - return decomposition - - -class TokenSwapperSynthesisPermutation(HighLevelSynthesisPlugin): - """The permutation synthesis plugin based on the token swapper algorithm. - - This plugin name is :``permutation.token_swapper`` which can be used as the key on - an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. - - In more detail, this plugin is used to synthesize objects of type `PermutationGate`. - When synthesis succeeds, the plugin outputs a quantum circuit consisting only of swap - gates. When synthesis does not succeed, the plugin outputs `None`. - - If either `coupling_map` or `qubits` is None, then the synthesized circuit - is not required to adhere to connectivity constraints, as is the case - when the synthesis is done before layout/routing. - - On the other hand, if both `coupling_map` and `qubits` are specified, the synthesized - circuit is supposed to adhere to connectivity constraints. At the moment, the - plugin only creates swap gates between qubits in `qubits`, i.e. it does not use - any other qubits in the coupling map (if such synthesis is not possible, the - plugin outputs `None`). - - The plugin supports the following plugin-specific options: - - * trials: The number of trials for the token swapper to perform the mapping. The - circuit with the smallest number of SWAPs is returned. - * seed: The argument to the token swapper specifying the seed for random trials. - * parallel_threshold: The argument to the token swapper specifying the number of nodes - in the graph beyond which the algorithm will use parallel processing. - - For more details on the token swapper algorithm, see to the paper: - `arXiv:1902.09102 `__. - """ - - def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): - """Run synthesis for the given Permutation.""" - - trials = options.get("trials", 5) - seed = options.get("seed", 0) - parallel_threshold = options.get("parallel_threshold", 50) - - pattern = high_level_object.pattern - pattern_as_dict = {j: i for i, j in enumerate(pattern)} - - # When the plugin is called from the HighLevelSynthesis transpiler pass, - # the coupling map already takes target into account. - if coupling_map is None or qubits is None: - # The abstract synthesis uses a fully connected coupling map, allowing - # arbitrary connections between qubits. - used_coupling_map = CouplingMap.from_full(len(pattern)) - else: - # The concrete synthesis uses the coupling map restricted to the set of - # qubits over which the permutation gate is defined. If we allow using other - # qubits in the coupling map, replacing the node in the DAGCircuit that - # defines this PermutationGate by the DAG corresponding to the constructed - # decomposition becomes problematic. Note that we allow the reduced - # coupling map to be disconnected. - used_coupling_map = coupling_map.reduce(qubits, check_if_connected=False) - - graph = used_coupling_map.graph.to_undirected() - swapper = ApproximateTokenSwapper(graph, seed=seed) - - try: - swapper_result = swapper.map( - pattern_as_dict, trials, parallel_threshold=parallel_threshold - ) - except rx.InvalidMapping: - swapper_result = None - - if swapper_result is not None: - decomposition = QuantumCircuit(len(graph.node_indices())) - for swap in swapper_result: - decomposition.swap(*swap) - return decomposition - - return None - - def _instruction_to_circuit(inst: Instruction) -> QuantumCircuit: circuit = QuantumCircuit(inst.num_qubits, inst.num_clbits) circuit.append(inst, circuit.qubits, circuit.clbits) diff --git a/qiskit/transpiler/passes/synthesis/hls_plugins.py b/qiskit/transpiler/passes/synthesis/hls_plugins.py new file mode 100644 index 000000000000..3dce030c1982 --- /dev/null +++ b/qiskit/transpiler/passes/synthesis/hls_plugins.py @@ -0,0 +1,928 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022, 2023. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + + +""" + +High Level Synthesis Plugins +----------------------------- + +Clifford Synthesis +'''''''''''''''''' + +.. list-table:: Plugins for :class:`qiskit.quantum_info.Clifford` (key = ``"clifford"``) + :header-rows: 1 + + * - Plugin name + - Plugin class + - Targeted connectivity + - Description + * - ``"ag"`` + - :class:`~.AGSynthesisClifford` + - all-to-all + - greedily optimizes CX-count + * - ``"bm"`` + - :class:`~.BMSynthesisClifford` + - all-to-all + - optimal count for `n=2,3`; used in ``"default"`` for `n=2,3` + * - ``"greedy"`` + - :class:`~.GreedySynthesisClifford` + - all-to-all + - greedily optimizes CX-count; used in ``"default"`` for `n>=4` + * - ``"layers"`` + - :class:`~.LayerSynthesisClifford` + - all-to-all + - + * - ``"lnn"`` + - :class:`~.LayerLnnSynthesisClifford` + - linear + - many CX-gates but guarantees CX-depth of at most `7*n+2` + * - ``"default"`` + - :class:`~.DefaultSynthesisClifford` + - all-to-all + - usually best for optimizing CX-count (and optimal CX-count for `n=2,3`) + +.. autosummary:: + :toctree: ../stubs/ + + AGSynthesisClifford + BMSynthesisClifford + GreedySynthesisClifford + LayerSynthesisClifford + LayerLnnSynthesisClifford + DefaultSynthesisClifford + + +Linear Function Synthesis +''''''''''''''''''''''''' + +.. list-table:: Plugins for :class:`.LinearFunction` (key = ``"linear"``) + :header-rows: 1 + + * - Plugin name + - Plugin class + - Targeted connectivity + - Description + * - ``"kms"`` + - :class:`~.KMSSynthesisLinearFunction` + - linear + - many CX-gates but guarantees CX-depth of at most `5*n` + * - ``"pmh"`` + - :class:`~.PMHSynthesisLinearFunction` + - all-to-all + - greedily optimizes CX-count; used in ``"default"`` + * - ``"default"`` + - :class:`~.DefaultSynthesisLinearFunction` + - all-to-all + - best for optimizing CX-count + +.. autosummary:: + :toctree: ../stubs/ + + KMSSynthesisLinearFunction + PMHSynthesisLinearFunction + DefaultSynthesisLinearFunction + + +Permutation Synthesis +''''''''''''''''''''' + +.. list-table:: Plugins for :class:`.PermutationGate` (key = ``"permutation"``) + :header-rows: 1 + + * - Plugin name + - Plugin class + - Targeted connectivity + - Description + * - ``"basic"`` + - :class:`~.BasicSynthesisPermutation` + - all-to-all + - optimal SWAP-count; used in ``"default"`` + * - ``"acg"`` + - :class:`~.ACGSynthesisPermutation` + - all-to-all + - guarantees SWAP-depth of at most `2` + * - ``"kms"`` + - :class:`~.KMSSynthesisPermutation` + - linear + - many SWAP-gates, but guarantees SWAP-depth of at most `n` + * - ``"token_swapper"`` + - :class:`~.TokenSwapperSynthesisPermutation` + - any + - greedily optimizes SWAP-count for arbitrary connectivity + * - ``"default"`` + - :class:`~.BasicSynthesisPermutation` + - all-to-all + - best for optimizing SWAP-count + +.. autosummary:: + :toctree: ../stubs/ + + BasicSynthesisPermutation + ACGSynthesisPermutation + KMSSynthesisPermutation + TokenSwapperSynthesisPermutation + + +QFT Synthesis +''''''''''''' + +.. list-table:: Plugins for :class:`.QFTGate` (key = ``"qft"``) + :header-rows: 1 + + * - Plugin name + - Plugin class + - Targeted connectivity + * - ``"full"`` + - :class:`~.QFTSynthesisFull` + - all-to-all + * - ``"line"`` + - :class:`~.QFTSynthesisLine` + - linear + * - ``"default"`` + - :class:`~.QFTSynthesisFull` + - all-to-all + +.. autosummary:: + :toctree: ../stubs/ + + QFTSynthesisFull + QFTSynthesisLine + + +MCX Synthesis +''''''''''''' + +The following table lists synthesis plugins available for an :class:`.MCXGate` gate +with `k` control qubits. If the available number of clean/dirty auxiliary qubits is +not sufficient, the corresponding synthesis method will return `None`. + +.. list-table:: Plugins for :class:`.MCXGate` (key = ``"mcx"``) + :header-rows: 1 + + * - Plugin name + - Plugin class + - Number of clean ancillas + - Number of dirty ancillas + - Description + * - ``"gray_code"`` + - :class:`~.MCXSynthesisGrayCode` + - `0` + - `0` + - exponentially many CX gates; use only for small values of `k` + * - ``"noaux_v24"`` + - :class:`~.MCXSynthesisNoAuxV24` + - `0` + - `0` + - quadratic number of CX gates; use instead of ``"gray_code"`` for large values of `k` + * - ``"n_clean_m15"`` + - :class:`~.MCXSynthesisNCleanM15` + - `k-2` + - `0` + - at most `6*k-6` CX gates + * - ``"n_dirty_i15"`` + - :class:`~.MCXSynthesisNDirtyI15` + - `0` + - `k-2` + - at most `8*k-6` CX gates + * - ``"1_clean_b95"`` + - :class:`~.MCXSynthesis1CleanB95` + - `1` + - `0` + - at most `16*k-8` CX gates + * - ``"default"`` + - :class:`~.MCXSynthesisDefault` + - any + - any + - chooses the best algorithm based on the ancillas available + +.. autosummary:: + :toctree: ../stubs/ + + MCXSynthesisGrayCode + MCXSynthesisNoAuxV24 + MCXSynthesisNCleanM15 + MCXSynthesisNDirtyI15 + MCXSynthesis1CleanB95 + MCXSynthesisDefault +""" + +import numpy as np +import rustworkx as rx + +from qiskit.circuit.quantumcircuit import QuantumCircuit +from qiskit.circuit.library import LinearFunction, QFTGate, MCXGate, C3XGate, C4XGate +from qiskit.transpiler.exceptions import TranspilerError +from qiskit.transpiler.coupling import CouplingMap + +from qiskit.synthesis.clifford import ( + synth_clifford_full, + synth_clifford_layers, + synth_clifford_depth_lnn, + synth_clifford_greedy, + synth_clifford_ag, + synth_clifford_bm, +) +from qiskit.synthesis.linear import ( + synth_cnot_count_full_pmh, + synth_cnot_depth_line_kms, + calc_inverse_matrix, +) +from qiskit.synthesis.linear.linear_circuits_utils import transpose_cx_circ +from qiskit.synthesis.permutation import ( + synth_permutation_basic, + synth_permutation_acg, + synth_permutation_depth_lnn_kms, +) +from qiskit.synthesis.qft import ( + synth_qft_full, + synth_qft_line, +) +from qiskit.synthesis.multi_controlled import ( + synth_mcx_n_dirty_i15, + synth_mcx_n_clean_m15, + synth_mcx_1_clean_b95, + synth_mcx_gray_code, + synth_mcx_noaux_v24, +) +from qiskit.transpiler.passes.routing.algorithms import ApproximateTokenSwapper +from .plugin import HighLevelSynthesisPlugin + + +class DefaultSynthesisClifford(HighLevelSynthesisPlugin): + """The default clifford synthesis plugin. + + For N <= 3 qubits this is the optimal CX cost decomposition by Bravyi, Maslov. + For N > 3 qubits this is done using the general non-optimal greedy compilation + routine from reference by Bravyi, Hu, Maslov, Shaydulin. + + This plugin name is :``clifford.default`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Clifford.""" + decomposition = synth_clifford_full(high_level_object) + return decomposition + + +class AGSynthesisClifford(HighLevelSynthesisPlugin): + """Clifford synthesis plugin based on the Aaronson-Gottesman method. + + This plugin name is :``clifford.ag`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Clifford.""" + decomposition = synth_clifford_ag(high_level_object) + return decomposition + + +class BMSynthesisClifford(HighLevelSynthesisPlugin): + """Clifford synthesis plugin based on the Bravyi-Maslov method. + + The method only works on Cliffords with at most 3 qubits, for which it + constructs the optimal CX cost decomposition. + + This plugin name is :``clifford.bm`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Clifford.""" + if high_level_object.num_qubits <= 3: + decomposition = synth_clifford_bm(high_level_object) + else: + decomposition = None + return decomposition + + +class GreedySynthesisClifford(HighLevelSynthesisPlugin): + """Clifford synthesis plugin based on the greedy synthesis + Bravyi-Hu-Maslov-Shaydulin method. + + This plugin name is :``clifford.greedy`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Clifford.""" + decomposition = synth_clifford_greedy(high_level_object) + return decomposition + + +class LayerSynthesisClifford(HighLevelSynthesisPlugin): + """Clifford synthesis plugin based on the Bravyi-Maslov method + to synthesize Cliffords into layers. + + This plugin name is :``clifford.layers`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Clifford.""" + decomposition = synth_clifford_layers(high_level_object) + return decomposition + + +class LayerLnnSynthesisClifford(HighLevelSynthesisPlugin): + """Clifford synthesis plugin based on the Bravyi-Maslov method + to synthesize Cliffords into layers, with each layer synthesized + adhering to LNN connectivity. + + This plugin name is :``clifford.lnn`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Clifford.""" + decomposition = synth_clifford_depth_lnn(high_level_object) + return decomposition + + +class DefaultSynthesisLinearFunction(HighLevelSynthesisPlugin): + """The default linear function synthesis plugin. + + This plugin name is :``linear_function.default`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given LinearFunction.""" + decomposition = synth_cnot_count_full_pmh(high_level_object.linear) + return decomposition + + +class KMSSynthesisLinearFunction(HighLevelSynthesisPlugin): + """Linear function synthesis plugin based on the Kutin-Moulton-Smithline method. + + This plugin name is :``linear_function.kms`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + The plugin supports the following plugin-specific options: + + * use_inverted: Indicates whether to run the algorithm on the inverse matrix + and to invert the synthesized circuit. + In certain cases this provides a better decomposition than the direct approach. + * use_transposed: Indicates whether to run the algorithm on the transposed matrix + and to invert the order of CX gates in the synthesized circuit. + In certain cases this provides a better decomposition than the direct approach. + + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given LinearFunction.""" + + if not isinstance(high_level_object, LinearFunction): + raise TranspilerError( + "PMHSynthesisLinearFunction only accepts objects of type LinearFunction" + ) + + use_inverted = options.get("use_inverted", False) + use_transposed = options.get("use_transposed", False) + + mat = high_level_object.linear.astype(bool, copy=False) + + if use_transposed: + mat = np.transpose(mat) + if use_inverted: + mat = calc_inverse_matrix(mat) + + decomposition = synth_cnot_depth_line_kms(mat) + + if use_transposed: + decomposition = transpose_cx_circ(decomposition) + if use_inverted: + decomposition = decomposition.inverse() + + return decomposition + + +class PMHSynthesisLinearFunction(HighLevelSynthesisPlugin): + """Linear function synthesis plugin based on the Patel-Markov-Hayes method. + + This plugin name is :``linear_function.pmh`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + The plugin supports the following plugin-specific options: + + * section size: The size of each section used in the Patel–Markov–Hayes algorithm [1]. + * use_inverted: Indicates whether to run the algorithm on the inverse matrix + and to invert the synthesized circuit. + In certain cases this provides a better decomposition than the direct approach. + * use_transposed: Indicates whether to run the algorithm on the transposed matrix + and to invert the order of CX gates in the synthesized circuit. + In certain cases this provides a better decomposition than the direct approach. + + References: + 1. Patel, Ketan N., Igor L. Markov, and John P. Hayes, + *Optimal synthesis of linear reversible circuits*, + Quantum Information & Computation 8.3 (2008): 282-294. + `arXiv:quant-ph/0302002 [quant-ph] `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given LinearFunction.""" + + if not isinstance(high_level_object, LinearFunction): + raise TranspilerError( + "PMHSynthesisLinearFunction only accepts objects of type LinearFunction" + ) + + section_size = options.get("section_size", 2) + use_inverted = options.get("use_inverted", False) + use_transposed = options.get("use_transposed", False) + + mat = high_level_object.linear.astype(bool, copy=False) + + if use_transposed: + mat = np.transpose(mat) + if use_inverted: + mat = calc_inverse_matrix(mat) + + decomposition = synth_cnot_count_full_pmh(mat, section_size=section_size) + + if use_transposed: + decomposition = transpose_cx_circ(decomposition) + if use_inverted: + decomposition = decomposition.inverse() + + return decomposition + + +class KMSSynthesisPermutation(HighLevelSynthesisPlugin): + """The permutation synthesis plugin based on the Kutin, Moulton, Smithline method. + + This plugin name is :``permutation.kms`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Permutation.""" + decomposition = synth_permutation_depth_lnn_kms(high_level_object.pattern) + return decomposition + + +class BasicSynthesisPermutation(HighLevelSynthesisPlugin): + """The permutation synthesis plugin based on sorting. + + This plugin name is :``permutation.basic`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Permutation.""" + decomposition = synth_permutation_basic(high_level_object.pattern) + return decomposition + + +class ACGSynthesisPermutation(HighLevelSynthesisPlugin): + """The permutation synthesis plugin based on the Alon, Chung, Graham method. + + This plugin name is :``permutation.acg`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Permutation.""" + decomposition = synth_permutation_acg(high_level_object.pattern) + return decomposition + + +class QFTSynthesisFull(HighLevelSynthesisPlugin): + """Synthesis plugin for QFT gates using all-to-all connectivity. + + This plugin name is :``qft.full`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + The plugin supports the following additional options: + + * reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``, + which is the default) or the "QFT-with-reversal" operation (if ``True``). + Some implementation of the ``QFTGate`` include a layer of swap gates at the end + of the synthesized circuit, which can in principle be dropped if the ``QFTGate`` + itself is the last gate in the circuit. + * approximation_degree (int): The degree of approximation (0 for no approximation). + It is possible to implement the QFT approximately by ignoring + controlled-phase rotations with the angle beneath a threshold. This is discussed + in more detail in [1] or [2]. + * insert_barriers (bool): If True, barriers are inserted as visualization improvement. + * inverse (bool): If True, the inverse Fourier transform is constructed. + * name (str): The name of the circuit. + + References: + 1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä, + *Approximate Quantum Fourier Transform and Decoherence*, + Physical Review A (1996). + `arXiv:quant-ph/9601018 [quant-ph] `_ + 2. Donny Cheung, + *Improved Bounds for the Approximate QFT* (2004), + `arXiv:quant-ph/0403071 [quant-ph] `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given QFTGate.""" + if not isinstance(high_level_object, QFTGate): + raise TranspilerError( + "The synthesis plugin 'qft.full` only applies to objects of type QFTGate." + ) + + reverse_qubits = options.get("reverse_qubits", False) + approximation_degree = options.get("approximation_degree", 0) + insert_barriers = options.get("insert_barriers", False) + inverse = options.get("inverse", False) + name = options.get("name", None) + + decomposition = synth_qft_full( + num_qubits=high_level_object.num_qubits, + do_swaps=not reverse_qubits, + approximation_degree=approximation_degree, + insert_barriers=insert_barriers, + inverse=inverse, + name=name, + ) + return decomposition + + +class QFTSynthesisLine(HighLevelSynthesisPlugin): + """Synthesis plugin for QFT gates using linear connectivity. + + This plugin name is :``qft.line`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + The plugin supports the following additional options: + + * reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``, + which is the default) or the "QFT-with-reversal" operation (if ``True``). + Some implementation of the ``QFTGate`` include a layer of swap gates at the end + of the synthesized circuit, which can in principle be dropped if the ``QFTGate`` + itself is the last gate in the circuit. + * approximation_degree (int): the degree of approximation (0 for no approximation). + It is possible to implement the QFT approximately by ignoring + controlled-phase rotations with the angle beneath a threshold. This is discussed + in more detail in [1] or [2]. + + References: + 1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä, + *Approximate Quantum Fourier Transform and Decoherence*, + Physical Review A (1996). + `arXiv:quant-ph/9601018 [quant-ph] `_ + 2. Donny Cheung, + *Improved Bounds for the Approximate QFT* (2004), + `arXiv:quant-ph/0403071 [quant-ph] `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given QFTGate.""" + if not isinstance(high_level_object, QFTGate): + raise TranspilerError( + "The synthesis plugin 'qft.line` only applies to objects of type QFTGate." + ) + + reverse_qubits = options.get("reverse_qubits", False) + approximation_degree = options.get("approximation_degree", 0) + + decomposition = synth_qft_line( + num_qubits=high_level_object.num_qubits, + do_swaps=not reverse_qubits, + approximation_degree=approximation_degree, + ) + return decomposition + + +class TokenSwapperSynthesisPermutation(HighLevelSynthesisPlugin): + """The permutation synthesis plugin based on the token swapper algorithm. + + This plugin name is :``permutation.token_swapper`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + In more detail, this plugin is used to synthesize objects of type `PermutationGate`. + When synthesis succeeds, the plugin outputs a quantum circuit consisting only of swap + gates. When synthesis does not succeed, the plugin outputs `None`. + + If either `coupling_map` or `qubits` is None, then the synthesized circuit + is not required to adhere to connectivity constraints, as is the case + when the synthesis is done before layout/routing. + + On the other hand, if both `coupling_map` and `qubits` are specified, the synthesized + circuit is supposed to adhere to connectivity constraints. At the moment, the + plugin only creates swap gates between qubits in `qubits`, i.e. it does not use + any other qubits in the coupling map (if such synthesis is not possible, the + plugin outputs `None`). + + The plugin supports the following plugin-specific options: + + * trials: The number of trials for the token swapper to perform the mapping. The + circuit with the smallest number of SWAPs is returned. + * seed: The argument to the token swapper specifying the seed for random trials. + * parallel_threshold: The argument to the token swapper specifying the number of nodes + in the graph beyond which the algorithm will use parallel processing. + + For more details on the token swapper algorithm, see to the paper: + `arXiv:1902.09102 `__. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given Permutation.""" + + trials = options.get("trials", 5) + seed = options.get("seed", 0) + parallel_threshold = options.get("parallel_threshold", 50) + + pattern = high_level_object.pattern + pattern_as_dict = {j: i for i, j in enumerate(pattern)} + + # When the plugin is called from the HighLevelSynthesis transpiler pass, + # the coupling map already takes target into account. + if coupling_map is None or qubits is None: + # The abstract synthesis uses a fully connected coupling map, allowing + # arbitrary connections between qubits. + used_coupling_map = CouplingMap.from_full(len(pattern)) + else: + # The concrete synthesis uses the coupling map restricted to the set of + # qubits over which the permutation gate is defined. If we allow using other + # qubits in the coupling map, replacing the node in the DAGCircuit that + # defines this PermutationGate by the DAG corresponding to the constructed + # decomposition becomes problematic. Note that we allow the reduced + # coupling map to be disconnected. + used_coupling_map = coupling_map.reduce(qubits, check_if_connected=False) + + graph = used_coupling_map.graph.to_undirected() + swapper = ApproximateTokenSwapper(graph, seed=seed) + + try: + swapper_result = swapper.map( + pattern_as_dict, trials, parallel_threshold=parallel_threshold + ) + except rx.InvalidMapping: + swapper_result = None + + if swapper_result is not None: + decomposition = QuantumCircuit(len(graph.node_indices())) + for swap in swapper_result: + decomposition.swap(*swap) + return decomposition + + return None + + +class MCXSynthesisNDirtyI15(HighLevelSynthesisPlugin): + r"""Synthesis plugin for a multi-controlled X gate based on the paper + by Iten et al. (2016). + + See [1] for details. + + This plugin name is :``mcx.n_dirty_i15`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis + method requires :math:`k - 2` additional dirty auxiliary qubits. The synthesized + circuit consists of :math:`2 * k - 1` qubits and at most :math:`8 * k - 6` CX gates. + + The plugin supports the following plugin-specific options: + + * num_clean_ancillas: The number of clean auxiliary qubits available. + * num_dirty_ancillas: The number of dirty auxiliary qubits available. + * relative_phase: When set to ``True``, the method applies the optimized multi-controlled + X gate up to a relative phase, in a way that, by lemma 8 of [1], the relative + phases of the ``action part`` cancel out with the phases of the ``reset part``. + * action_only: when set to ``True``, the method applies only the ``action part`` + of lemma 8 of [1]. + + References: + 1. Iten et. al., *Quantum Circuits for Isometries*, Phys. Rev. A 93, 032318 (2016), + `arXiv:1501.06911 `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given MCX gate.""" + + if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)): + # Unfortunately we occasionally have custom instructions called "mcx" + # which get wrongly caught by the plugin interface. A simple solution is + # to return None in this case, since HLS would proceed to examine + # their definition as it should. + return None + + num_ctrl_qubits = high_level_object.num_ctrl_qubits + num_clean_ancillas = options.get("num_clean_ancillas", 0) + num_dirty_ancillas = options.get("num_dirty_ancillas", 0) + relative_phase = options.get("relative_phase", False) + action_only = options.get("actions_only", False) + + if num_ctrl_qubits >= 3 and num_dirty_ancillas + num_clean_ancillas < num_ctrl_qubits - 2: + # This synthesis method is not applicable as there are not enough ancilla qubits + return None + + decomposition = synth_mcx_n_dirty_i15(num_ctrl_qubits, relative_phase, action_only) + return decomposition + + +class MCXSynthesisNCleanM15(HighLevelSynthesisPlugin): + r"""Synthesis plugin for a multi-controlled X gate based on the paper by + Maslov (2016). + + See [1] for details. + + This plugin name is :``mcx.n_clean_m15`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + For a multi-controlled X gate with :math:`k\ge 3` control qubits this synthesis + method requires :math:`k - 2` additional clean auxiliary qubits. The synthesized + circuit consists of :math:`2 * k - 1` qubits and at most :math:`6 * k - 6` CX gates. + + The plugin supports the following plugin-specific options: + + * num_clean_ancillas: The number of clean auxiliary qubits available. + + References: + 1. Maslov., Phys. Rev. A 93, 022311 (2016), + `arXiv:1508.03273 `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given MCX gate.""" + + if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)): + # Unfortunately we occasionally have custom instructions called "mcx" + # which get wrongly caught by the plugin interface. A simple solution is + # to return None in this case, since HLS would proceed to examine + # their definition as it should. + return None + + num_ctrl_qubits = high_level_object.num_ctrl_qubits + num_clean_ancillas = options.get("num_clean_ancillas", 0) + + if num_ctrl_qubits >= 3 and num_clean_ancillas < num_ctrl_qubits - 2: + # This synthesis method is not applicable as there are not enough ancilla qubits + return None + + decomposition = synth_mcx_n_clean_m15(num_ctrl_qubits) + return decomposition + + +class MCXSynthesis1CleanB95(HighLevelSynthesisPlugin): + r"""Synthesis plugin for a multi-controlled X gate based on the paper by + Barenco et al. (1995). + + See [1] for details. + + This plugin name is :``mcx.1_clean_b95`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + For a multi-controlled X gate with :math:`k\ge 5` control qubits this synthesis + method requires a single additional clean auxiliary qubit. The synthesized + circuit consists of :math:`k + 2` qubits and at most :math:`16 * k - 8` CX gates. + + The plugin supports the following plugin-specific options: + + * num_clean_ancillas: The number of clean auxiliary qubits available. + + References: + 1. Barenco et. al., Phys.Rev. A52 3457 (1995), + `arXiv:quant-ph/9503016 `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given MCX gate.""" + + if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)): + # Unfortunately we occasionally have custom instructions called "mcx" + # which get wrongly caught by the plugin interface. A simple solution is + # to return None in this case, since HLS would proceed to examine + # their definition as it should. + return None + + num_ctrl_qubits = high_level_object.num_ctrl_qubits + + if num_ctrl_qubits <= 2: + # The method requires at least 3 control qubits + return None + + num_clean_ancillas = options.get("num_clean_ancillas", 0) + + if num_ctrl_qubits >= 5 and num_clean_ancillas == 0: + # This synthesis method is not applicable as there are not enough ancilla qubits + return None + + decomposition = synth_mcx_1_clean_b95(num_ctrl_qubits) + return decomposition + + +class MCXSynthesisGrayCode(HighLevelSynthesisPlugin): + r"""Synthesis plugin for a multi-controlled X gate based on the Gray code. + + This plugin name is :``mcx.gray_code`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + For a multi-controlled X gate with :math:`k` control qubits this synthesis + method requires no additional clean auxiliary qubits. The synthesized + circuit consists of :math:`k + 1` qubits. + + It is not recommended to use this method for large values of :math:`k + 1` + as it produces exponentially many gates. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given MCX gate.""" + + if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)): + # Unfortunately we occasionally have custom instructions called "mcx" + # which get wrongly caught by the plugin interface. A simple solution is + # to return None in this case, since HLS would proceed to examine + # their definition as it should. + return None + + num_ctrl_qubits = high_level_object.num_ctrl_qubits + decomposition = synth_mcx_gray_code(num_ctrl_qubits) + return decomposition + + +class MCXSynthesisNoAuxV24(HighLevelSynthesisPlugin): + r"""Synthesis plugin for a multi-controlled X gate based on the + implementation for MCPhaseGate, which is in turn based on the + paper by Vale et al. (2024). + + See [1] for details. + + This plugin name is :``mcx.noaux_v24`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + + For a multi-controlled X gate with :math:`k` control qubits this synthesis + method requires no additional clean auxiliary qubits. The synthesized + circuit consists of :math:`k + 1` qubits. + + References: + 1. Vale et. al., *Circuit Decomposition of Multicontrolled Special Unitary + Single-Qubit Gates*, IEEE TCAD 43(3) (2024), + `arXiv:2302.06377 `_ + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given MCX gate.""" + + if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)): + # Unfortunately we occasionally have custom instructions called "mcx" + # which get wrongly caught by the plugin interface. A simple solution is + # to return None in this case, since HLS would proceed to examine + # their definition as it should. + return None + + num_ctrl_qubits = high_level_object.num_ctrl_qubits + decomposition = synth_mcx_noaux_v24(num_ctrl_qubits) + return decomposition + + +class MCXSynthesisDefault(HighLevelSynthesisPlugin): + r"""The default synthesis plugin for a multi-controlled X gate. + + This plugin name is :``mcx.default`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options): + """Run synthesis for the given MCX gate.""" + + if not isinstance(high_level_object, (MCXGate, C3XGate, C4XGate)): + # Unfortunately we occasionally have custom instructions called "mcx" + # which get wrongly caught by the plugin interface. A simple solution is + # to return None in this case, since HLS would proceed to examine + # their definition as it should. + return None + + # Iteratively run other synthesis methods available + + if ( + decomposition := MCXSynthesisNCleanM15().run( + high_level_object, coupling_map, target, qubits, **options + ) + ) is not None: + return decomposition + + if ( + decomposition := MCXSynthesisNDirtyI15().run( + high_level_object, coupling_map, target, qubits, **options + ) + ) is not None: + return decomposition + + if ( + decomposition := MCXSynthesis1CleanB95().run( + high_level_object, coupling_map, target, qubits, **options + ) + ) is not None: + return decomposition + + return MCXSynthesisNoAuxV24().run( + high_level_object, coupling_map, target, qubits, **options + ) diff --git a/qiskit/transpiler/passes/synthesis/plugin.py b/qiskit/transpiler/passes/synthesis/plugin.py index c57c6d76f9fb..a56c48e9cf96 100644 --- a/qiskit/transpiler/passes/synthesis/plugin.py +++ b/qiskit/transpiler/passes/synthesis/plugin.py @@ -378,7 +378,7 @@ def run(self, high_level_object, coupling_map=None, target=None, qubits=None, ** is :class:`~.KMSSynthesisPermutation`. This particular synthesis algorithm created a circuit adhering to the linear nearest-neighbor connectivity. -.. automodule:: qiskit.transpiler.passes.synthesis.high_level_synthesis +.. automodule:: qiskit.transpiler.passes.synthesis.hls_plugins :no-members: :no-inherited-members: :no-special-members: diff --git a/releasenotes/notes/add-mcx-plugins-85e5b248692a36db.yaml b/releasenotes/notes/add-mcx-plugins-85e5b248692a36db.yaml new file mode 100644 index 000000000000..84ec35942d0a --- /dev/null +++ b/releasenotes/notes/add-mcx-plugins-85e5b248692a36db.yaml @@ -0,0 +1,45 @@ +--- +features_synthesis: + - | + Added synthesis functions :func:`.synth_mcx_gray_code` and :func:`.synth_mcx_noaux_v24` + that synthesize multi-controlled X gates. These functions do not require additional + ancilla qubits. + - | + Added synthesis functions :func:`.synth_c3x` and :func:`.synth_c4x` that + synthesize 3-controlled and 4-controlled X-gates respectively. +features_transpiler: + - | + Added multiple high-level-synthesis plugins for synthesizing an :class:`.MCXGate`: + + * :class:`.MCXSynthesisNCleanM15`, based on :func:`.synth_mcx_n_clean_m15`. + * :class:`.MCXSynthesisNDirtyI15`, based on :func:`.synth_mcx_n_dirty_i15`. + * :class:`.MCXSynthesis1CleanB95`, based on :func:`.synth_mcx_1_clean_b95`. + * :class:`.MCXSynthesisNoAuxV24`, based on :func:`.synth_mcx_noaux_v24`. + * :class:`.MCXSynthesisGrayCode`, based on :func:`.synth_mcx_gray_code`. + + As well: + + * :class:`.MCXSynthesisDefault`, choosing the most efficient synthesis + method based on the number of clean and dirty ancilla qubits available. + + As an example, consider how the transpilation of the following circuit:: + + from qiskit.circuit import QuantumCircuit + from qiskit.compiler import transpile + + qc = QuantumCircuit(7) + qc.x(0) + qc.mcx([0, 1, 2, 3], [4]) + qc.mcx([0, 1, 2, 3, 4], [5]) + qc.mcx([0, 1, 2, 3, 4, 5], [6]) + + transpile(qc) + + For the first MCX gate, qubits ``5`` and ``6`` can be used as clean + ancillas, and the best available synthesis method ``synth_mcx_n_clean_m15`` + will get chosen. + For the second MCX gate, qubit ``6`` can be used as a clean ancilla, + the method ``synth_mcx_n_clean_m15`` no longer applies, so the method + ``synth_mcx_1_clean_b95`` will get chosen. + For the third MCX gate, there are no ancilla qubits, and the method + ``synth_mcx_noaux_v24`` will get chosen. diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py index 5f01e5c647a6..984851e00388 100644 --- a/test/python/circuit/test_circuit_qasm.py +++ b/test/python/circuit/test_circuit_qasm.py @@ -394,14 +394,13 @@ def test_circuit_qasm_with_mcx_gate(self): # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition - pattern = r"""OPENQASM 2.0; + expected_qasm = """OPENQASM 2.0; include "qelib1.inc"; -gate mcx q0,q1,q2,q3 { h q3; p\(pi/8\) q0; p\(pi/8\) q1; p\(pi/8\) q2; p\(pi/8\) q3; cx q0,q1; p\(-pi/8\) q1; cx q0,q1; cx q1,q2; p\(-pi/8\) q2; cx q0,q2; p\(pi/8\) q2; cx q1,q2; p\(-pi/8\) q2; cx q0,q2; cx q2,q3; p\(-pi/8\) q3; cx q1,q3; p\(pi/8\) q3; cx q2,q3; p\(-pi/8\) q3; cx q0,q3; p\(pi/8\) q3; cx q2,q3; p\(-pi/8\) q3; cx q1,q3; p\(pi/8\) q3; cx q2,q3; p\(-pi/8\) q3; cx q0,q3; h q3; } -gate (?Pmcx_[0-9]*) q0,q1,q2,q3 { mcx q0,q1,q2,q3; } -qreg q\[4\]; -(?P=mcx_id) q\[0\],q\[1\],q\[2\],q\[3\];""" - expected_qasm = re.compile(pattern, re.MULTILINE) - self.assertRegex(dumps(qc), expected_qasm) +gate mcx q0,q1,q2,q3 { h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; } +qreg q[4]; +mcx q[0],q[1],q[2],q[3];""" + + self.assertEqual(dumps(qc), expected_qasm) def test_circuit_qasm_with_mcx_gate_variants(self): """Test circuit qasm() method with MCXGrayCode, MCXRecursive, MCXVChain""" @@ -420,8 +419,7 @@ def test_circuit_qasm_with_mcx_gate_variants(self): include "qelib1.inc"; gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }} -gate mcx q0,q1,q2,q3 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} -gate mcx_vchain q0,q1,q2,q3,q4 {{ mcx q0,q1,q2,q3; }} +gate mcx_vchain q0,q1,q2,q3,q4 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} gate mcx_vchain_{mcx_vchain_id} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; diff --git a/test/python/qasm2/test_export.py b/test/python/qasm2/test_export.py index 0bba2f5c47e0..8de4bb8eb34f 100644 --- a/test/python/qasm2/test_export.py +++ b/test/python/qasm2/test_export.py @@ -387,14 +387,12 @@ def test_mcx_gate(self): # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition - pattern = r"""OPENQASM 2.0; + expected_qasm = """OPENQASM 2.0; include "qelib1.inc"; -gate mcx q0,q1,q2,q3 { h q3; p\(pi/8\) q0; p\(pi/8\) q1; p\(pi/8\) q2; p\(pi/8\) q3; cx q0,q1; p\(-pi/8\) q1; cx q0,q1; cx q1,q2; p\(-pi/8\) q2; cx q0,q2; p\(pi/8\) q2; cx q1,q2; p\(-pi/8\) q2; cx q0,q2; cx q2,q3; p\(-pi/8\) q3; cx q1,q3; p\(pi/8\) q3; cx q2,q3; p\(-pi/8\) q3; cx q0,q3; p\(pi/8\) q3; cx q2,q3; p\(-pi/8\) q3; cx q1,q3; p\(pi/8\) q3; cx q2,q3; p\(-pi/8\) q3; cx q0,q3; h q3; } -gate (?Pmcx_[0-9]*) q0,q1,q2,q3 { mcx q0,q1,q2,q3; } -qreg q\[4\]; -(?P=mcx_id) q\[0\],q\[1\],q\[2\],q\[3\];""" - expected_qasm = re.compile(pattern, re.MULTILINE) - self.assertRegex(qasm2.dumps(qc), expected_qasm) +gate mcx q0,q1,q2,q3 { h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; } +qreg q[4]; +mcx q[0],q[1],q[2],q[3];""" + self.assertEqual(qasm2.dumps(qc), expected_qasm) def test_mcx_gate_variants(self): n = 5 @@ -406,13 +404,11 @@ def test_mcx_gate_variants(self): # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition - expected_qasm = f"""\ -OPENQASM 2.0; + expected_qasm = f"""OPENQASM 2.0; include "qelib1.inc"; gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }} -gate mcx q0,q1,q2,q3 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} -gate mcx_vchain q0,q1,q2,q3,q4 {{ mcx q0,q1,q2,q3; }} +gate mcx_vchain q0,q1,q2,q3,q4 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} gate mcx_vchain_{mcx_vchain_id} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; diff --git a/test/python/transpiler/test_decompose.py b/test/python/transpiler/test_decompose.py index 7b364f3ac10f..1223b37ca3ff 100644 --- a/test/python/transpiler/test_decompose.py +++ b/test/python/transpiler/test_decompose.py @@ -145,7 +145,7 @@ def test_decompose_oversized_instruction(self): self.assertEqual(qc1, output) def test_decomposition_preserves_qregs_order(self): - """Test decomposing a gate preserves it's definition registers order""" + """Test decomposing a gate preserves the order of registers in its definition""" qr = QuantumRegister(2, "qr1") qc1 = QuantumCircuit(qr) qc1.cx(1, 0) diff --git a/test/python/transpiler/test_high_level_synthesis.py b/test/python/transpiler/test_high_level_synthesis.py index 97c0b58bb377..f3b11c98bfc7 100644 --- a/test/python/transpiler/test_high_level_synthesis.py +++ b/test/python/transpiler/test_high_level_synthesis.py @@ -44,9 +44,10 @@ CU1Gate, QFTGate, IGate, + MCXGate, ) from qiskit.circuit.library.generalized_gates import LinearFunction -from qiskit.quantum_info import Clifford +from qiskit.quantum_info import Clifford, Operator, Statevector from qiskit.synthesis.linear import random_invertible_binary_matrix from qiskit.compiler import transpile from qiskit.exceptions import QiskitError @@ -59,13 +60,20 @@ high_level_synthesis_plugin_names, ) from qiskit.transpiler.passes.synthesis.high_level_synthesis import HighLevelSynthesis, HLSConfig +from qiskit.transpiler.passes.synthesis.hls_plugins import ( + MCXSynthesis1CleanB95, + MCXSynthesisNCleanM15, + MCXSynthesisNDirtyI15, + MCXSynthesisGrayCode, + MCXSynthesisDefault, + MCXSynthesisNoAuxV24, +) from qiskit.circuit.annotated_operation import ( AnnotatedOperation, ControlModifier, InverseModifier, PowerModifier, ) -from qiskit.quantum_info import Operator from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.circuit.library.standard_gates.equivalence_library import ( StandardEquivalenceLibrary as std_eqlib, @@ -1364,8 +1372,23 @@ def test_definition_with_annotations(self): lazy_gate3 = AnnotatedOperation(custom_gate, ControlModifier(2)) circuit = QuantumCircuit(6) circuit.append(lazy_gate3, [0, 1, 2, 3, 4, 5]) - transpiled_circuit = HighLevelSynthesis(basis_gates=["cx", "u"])(circuit) - self.assertEqual(Operator(circuit), Operator(transpiled_circuit)) + + with self.subTest(qubits_initially_zero=False): + # When transpiling without assuming that qubits are initially zero, + # we should have that the Operators before and after are equal. + transpiled_circuit = HighLevelSynthesis( + basis_gates=["cx", "u"], qubits_initially_zero=False + )(circuit) + self.assertEqual(Operator(circuit), Operator(transpiled_circuit)) + + with self.subTest(qubits_initially_zero=True): + # When transpiling assuming that qubits are initially zero, + # we should have that the Statevectors before and after + # are equal (but not the full Operators). + transpiled_circuit = HighLevelSynthesis( + basis_gates=["cx", "u"], qubits_initially_zero=True + )(circuit) + self.assertEqual(Statevector(circuit), Statevector(transpiled_circuit)) def test_definition_with_high_level_objects(self): """Test annotated gates with definitions involving annotations and @@ -2287,5 +2310,148 @@ def test_qft_line_plugin_annotated_qft(self, qft_plugin_name): self.assertEqual(Operator(qc), Operator(qct)) +@ddt +class TestMCXSynthesisPlugins(QiskitTestCase): + """Tests related to plugins for MCXGate.""" + + def test_supported_names(self): + """Test that there is a default synthesis plugin for MCXGate.""" + supported_plugin_names = high_level_synthesis_plugin_names("mcx") + self.assertIn("default", supported_plugin_names) + + def test_mcx_plugins_applicability(self): + """Test applicability of MCX synthesis plugins for MCX gates.""" + gate = MCXGate(5) + + with self.subTest(method="n_clean_m15", num_clean_ancillas=4, num_dirty_ancillas=4): + # should have a decomposition + decomposition = MCXSynthesisNCleanM15().run( + gate, num_clean_ancillas=4, num_dirty_ancillas=4 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="n_clean_m15", num_clean_ancillas=2, num_dirty_ancillas=4): + # should not have a decomposition + decomposition = MCXSynthesisNCleanM15().run( + gate, num_clean_ancillas=2, num_dirty_ancillas=4 + ) + self.assertIsNone(decomposition) + + with self.subTest(method="n_dirty_i15", num_clean_ancillas=4, num_dirty_ancillas=4): + # should have a decomposition + decomposition = MCXSynthesisNDirtyI15().run( + gate, num_clean_ancillas=4, num_dirty_ancillas=4 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="n_dirty_i15", num_clean_ancillas=2, num_dirty_ancillas=2): + # should have a decomposition + decomposition = MCXSynthesisNDirtyI15().run( + gate, num_clean_ancillas=2, num_dirty_ancillas=2 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="n_dirty_i15", num_clean_ancillas=1, num_dirty_ancillas=1): + # should not have a decomposition + decomposition = MCXSynthesisNDirtyI15().run( + gate, num_clean_ancillas=1, num_dirty_ancillas=1 + ) + self.assertIsNone(decomposition) + + with self.subTest(method="1_clean_b95", num_clean_ancillas=1, num_dirty_ancillas=0): + # should have a decomposition + decomposition = MCXSynthesis1CleanB95().run( + gate, num_clean_ancillas=1, num_dirty_ancillas=0 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="1_clean_b95", num_clean_ancillas=0, num_dirty_ancillas=1): + # should not have a decomposition + decomposition = MCXSynthesis1CleanB95().run( + gate, num_clean_ancillas=0, num_dirty_ancillas=1 + ) + self.assertIsNone(decomposition) + + with self.subTest(method="noaux_v24", num_clean_ancillas=1, num_dirty_ancillas=1): + # should have a decomposition + decomposition = MCXSynthesisNoAuxV24().run( + gate, num_clean_ancillas=1, num_dirty_ancillas=1 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="noaux_v24", num_clean_ancillas=0, num_dirty_ancillas=0): + # should have a decomposition + decomposition = MCXSynthesisNoAuxV24().run( + gate, num_clean_ancillas=0, num_dirty_ancillas=0 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="gray_code", num_clean_ancillas=1, num_dirty_ancillas=1): + # should have a decomposition + decomposition = MCXSynthesisGrayCode().run( + gate, num_clean_ancillas=1, num_dirty_ancillas=1 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="gray_code", num_clean_ancillas=0, num_dirty_ancillas=0): + # should have a decomposition + decomposition = MCXSynthesisGrayCode().run( + gate, num_clean_ancillas=0, num_dirty_ancillas=0 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="default", num_clean_ancillas=1, num_dirty_ancillas=1): + # should have a decomposition + decomposition = MCXSynthesisDefault().run( + gate, num_clean_ancillas=1, num_dirty_ancillas=1 + ) + self.assertIsNotNone(decomposition) + + with self.subTest(method="default", num_clean_ancillas=0, num_dirty_ancillas=0): + # should have a decomposition + decomposition = MCXSynthesisDefault().run( + gate, num_clean_ancillas=0, num_dirty_ancillas=0 + ) + self.assertIsNotNone(decomposition) + + @data("n_clean_m15", "n_dirty_i15", "1_clean_b95", "noaux_v24", "gray_code", "default") + def test_mcx_plugins_correctness_from_arbitrary(self, mcx_plugin_name): + """Test that all plugins return a correct Operator when qubits are not + initially zero.""" + qc = QuantumCircuit(6) + qc.h(0) + qc.cx(0, 1) + qc.mcx(control_qubits=[0, 1, 2], target_qubit=[3]) + qc.mcx(control_qubits=[2, 3, 4, 5], target_qubit=[1]) + qc.mcx(control_qubits=[5, 4, 3, 2, 1], target_qubit=[0]) + hls_config = HLSConfig(mcx=[mcx_plugin_name]) + hls_pass = HighLevelSynthesis(hls_config=hls_config, qubits_initially_zero=False) + qct = hls_pass(qc) + self.assertEqual(Operator(qc), Operator(qct)) + + @data("n_clean_m15", "n_dirty_i15", "1_clean_b95", "noaux_v24", "gray_code", "default") + def test_mcx_plugins_correctness_from_zero(self, mcx_plugin_name): + """Test that all plugins return a correct Statevector when qubits are + initially zero.""" + qc = QuantumCircuit(6) + qc.h(0) + qc.cx(0, 1) + qc.mcx(control_qubits=[0, 1, 2], target_qubit=[3]) + qc.mcx(control_qubits=[2, 3, 4, 5], target_qubit=[1]) + qc.mcx(control_qubits=[5, 4, 3, 2, 1], target_qubit=[0]) + hls_config = HLSConfig(mcx=[mcx_plugin_name]) + hls_pass = HighLevelSynthesis(hls_config=hls_config, qubits_initially_zero=True) + qct = hls_pass(qc) + self.assertEqual(Statevector(qc), Statevector(qct)) + + def test_annotated_mcx(self): + """Test synthesis of annotated MCX gates.""" + qc = QuantumCircuit(6) + qc.h(0) + qc.append(MCXGate(3).inverse(annotated=True).control(2, annotated=True), [0, 1, 2, 3, 4, 5]) + qct = transpile(qc, qubits_initially_zero=False) + self.assertEqual(Operator(qc), Operator(qct)) + + if __name__ == "__main__": unittest.main() From 1e7c10f7a5a4902223ca2649f42c6b8d68d05361 Mon Sep 17 00:00:00 2001 From: abbycross Date: Thu, 22 Aug 2024 15:23:11 -0400 Subject: [PATCH 18/85] Sections in docs.quantum.ibm.com have been renamed (#13017) --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f94ee26f4498..08ca898577d7 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,4 +2,4 @@ blank_issues_enabled: true contact_links: - name: Non-API docs issues url: https://github.com/Qiskit/documentation/issues/new/choose - about: Open an issue about documentation in the Start, Build, Transpile, Verify, Run, or Migration guides sections of docs.quantum.ibm.com (non-API documentation) \ No newline at end of file + about: Open an issue about documentation in the guides and additional resources sections of docs.quantum.ibm.com (non-API documentation) From 6b6efc7d547e5baef7d906c850e2bc69ed6430fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= <57907331+ElePT@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:04:35 +0200 Subject: [PATCH 19/85] Filter aer warnings in deprecated `FakeBackend` V1 class (#13018) * Filter aer warnings in fake backend for the deprecated V1 path * Filter warnings in QiskitTestCase instead of catching them --- test/utils/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/utils/base.py b/test/utils/base.py index e1b2180aac4e..0038f7772ebf 100644 --- a/test/utils/base.py +++ b/test/utils/base.py @@ -156,6 +156,14 @@ def setUpClass(cls): module="qiskit_aer", ) + # Safe to remove once `FakeBackend` is removed (2.0) + warnings.filterwarnings( + "ignore", # If "default", it floods the CI output + category=DeprecationWarning, + message=r".*from_backend using V1 based backend is deprecated as of Aer 0.15*", + module="qiskit.providers.fake_provider.fake_backend", + ) + allow_DeprecationWarning_message = [ r"The property ``qiskit\.circuit\.bit\.Bit\.(register|index)`` is deprecated.*", ] From a4bf87bf66df53a6984bd2fd82c19125339cc431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= <57907331+ElePT@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:31:24 +0200 Subject: [PATCH 20/85] Fix Rust-space `TwoQubitBasisDecomposer` for non-standard KAK gate (#13014) * Get rid of encoded assumption in TwoQubitBasisDecomposer that the given KAK gate is a Rust-space StandardGate * Improve unit test * Update test/python/synthesis/test_synthesis.py Co-authored-by: Matthew Treinish --------- Co-authored-by: Matthew Treinish --- crates/accelerate/src/two_qubit_decompose.rs | 66 +++++++++++++------ ...ser-non-std-kak-gate-edc69ffb5d9ef302.yaml | 5 ++ test/python/synthesis/test_synthesis.py | 15 +++++ 3 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 releasenotes/notes/fix-2q-basis-decomposer-non-std-kak-gate-edc69ffb5d9ef302.yaml diff --git a/crates/accelerate/src/two_qubit_decompose.rs b/crates/accelerate/src/two_qubit_decompose.rs index 2072c5034ff7..77ebb3f9433c 100644 --- a/crates/accelerate/src/two_qubit_decompose.rs +++ b/crates/accelerate/src/two_qubit_decompose.rs @@ -55,6 +55,7 @@ use qiskit_circuit::circuit_data::CircuitData; use qiskit_circuit::circuit_instruction::OperationFromPython; use qiskit_circuit::gate_matrix::{CX_GATE, H_GATE, ONE_QUBIT_IDENTITY, SX_GATE, X_GATE}; use qiskit_circuit::operations::{Param, StandardGate}; +use qiskit_circuit::packed_instruction::PackedOperation; use qiskit_circuit::slice::{PySequenceIndex, SequenceIndex}; use qiskit_circuit::util::{c64, GateArray1Q, GateArray2Q, C_M_ONE, C_ONE, C_ZERO, IM, M_IM}; use qiskit_circuit::Qubit; @@ -2063,26 +2064,51 @@ impl TwoQubitBasisDecomposer { ) -> PyResult { let kak_gate = kak_gate.extract::(py)?; let sequence = self.__call__(unitary, basis_fidelity, approximate, _num_basis_uses)?; - CircuitData::from_standard_gates( - py, - 2, - sequence - .gates - .into_iter() - .map(|(gate, params, qubits)| match gate { - Some(gate) => ( - gate, - params.into_iter().map(Param::Float).collect(), - qubits.into_iter().map(|x| Qubit(x.into())).collect(), - ), - None => ( - kak_gate.operation.standard_gate(), - kak_gate.params.clone(), - qubits.into_iter().map(|x| Qubit(x.into())).collect(), - ), - }), - Param::Float(sequence.global_phase), - ) + match kak_gate.operation.try_standard_gate() { + Some(std_kak_gate) => CircuitData::from_standard_gates( + py, + 2, + sequence + .gates + .into_iter() + .map(|(gate, params, qubits)| match gate { + Some(gate) => ( + gate, + params.into_iter().map(Param::Float).collect(), + qubits.into_iter().map(|x| Qubit(x.into())).collect(), + ), + None => ( + std_kak_gate, + kak_gate.params.clone(), + qubits.into_iter().map(|x| Qubit(x.into())).collect(), + ), + }), + Param::Float(sequence.global_phase), + ), + None => CircuitData::from_packed_operations( + py, + 2, + 0, + sequence + .gates + .into_iter() + .map(|(gate, params, qubits)| match gate { + Some(gate) => ( + PackedOperation::from_standard(gate), + params.into_iter().map(Param::Float).collect(), + qubits.into_iter().map(|x| Qubit(x.into())).collect(), + Vec::new(), + ), + None => ( + kak_gate.operation.clone(), + kak_gate.params.clone(), + qubits.into_iter().map(|x| Qubit(x.into())).collect(), + Vec::new(), + ), + }), + Param::Float(sequence.global_phase), + ), + } } fn num_basis_gates(&self, unitary: PyReadonlyArray2) -> usize { diff --git a/releasenotes/notes/fix-2q-basis-decomposer-non-std-kak-gate-edc69ffb5d9ef302.yaml b/releasenotes/notes/fix-2q-basis-decomposer-non-std-kak-gate-edc69ffb5d9ef302.yaml new file mode 100644 index 000000000000..903b9ceac2a2 --- /dev/null +++ b/releasenotes/notes/fix-2q-basis-decomposer-non-std-kak-gate-edc69ffb5d9ef302.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed a bug in :class:`.TwoQubitBasisDecomposer` where the Rust-based code + would panic if the given KAK gate wasn't a Rust-space :class:`StandardGate`. \ No newline at end of file diff --git a/test/python/synthesis/test_synthesis.py b/test/python/synthesis/test_synthesis.py index 05739db249b7..b4fac3f427f0 100644 --- a/test/python/synthesis/test_synthesis.py +++ b/test/python/synthesis/test_synthesis.py @@ -1270,6 +1270,21 @@ def test_use_dag(self, euler_bases, kak_gates, seed): requested_basis = set(oneq_gates + [kak_gate_name]) self.assertTrue(decomposition_basis.issubset(requested_basis)) + def test_non_std_gate(self): + """Test that the TwoQubitBasisDecomposer class can be correctly instantiated with a + non-standard KAK gate. + + Reproduce from: https://github.com/Qiskit/qiskit/issues/12998 + """ + # note that `CXGate(ctrl_state=0)` is not handled as a "standard" gate. + decomposer = TwoQubitBasisDecomposer(CXGate(ctrl_state=0)) + unitary = SwapGate().to_matrix() + decomposed_unitary = decomposer(unitary) + self.assertEqual(Operator(unitary), Operator(decomposed_unitary)) + self.assertNotIn("swap", decomposed_unitary.count_ops()) + self.assertNotIn("cx", decomposed_unitary.count_ops()) + self.assertEqual(3, decomposed_unitary.count_ops()["cx_o0"]) + @ddt class TestPulseOptimalDecompose(CheckDecompositions): From d3040a0b7f25d268c6342011d2d12d42354ed3bc Mon Sep 17 00:00:00 2001 From: Kevin Hartman Date: Fri, 23 Aug 2024 12:40:59 -0400 Subject: [PATCH 21/85] [DAGCircuit Oxidation] Port `DAGCircuit` to Rust (#12550) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Port DAGCircuit to Rust This commit migrates the entirety of the `DAGCircuit` class to Rust. It fully replaces the Python version of the class. The primary advantage of this migration is moving from a Python space rustworkx directed graph representation to a Rust space petgraph (the upstream library for rustworkx) directed graph. Moving the graph data structure to rust enables us to directly interact with the DAG directly from transpiler passes in Rust in the future. This will enable a significant speed-up in those transpiler passes. Additionally, this should also improve the memory footprint as the DAGCircuit no longer stores `DAGNode` instances, and instead stores a lighter enum NodeType, which simply contains a `PackedInstruction` or the wire objects directly. Internally, the new Rust-based `DAGCircuit` uses a `petgraph::StableGraph` with node weights of type `NodeType` and edge weights of type `Wire`. The NodeType enum contains variants for `QubitIn`, `QubitOut`, `ClbitIn`, `ClbitOut`, and `Operation`, which should save us from all of the `isinstance` checking previously needed when working with `DAGNode` Python instances. The `Wire` enum contains variants `Qubit`, `Clbit`, and `Var`. As the full Qiskit data model is not rust-native at this point while all the class code in the `DAGCircuit` exists in Rust now, there are still sections that rely on Python or actively run Python code via Rust to function. These typically involve anything that uses `condition`, control flow, classical vars, calibrations, bit/register manipulation, etc. In the future as we either migrate this functionality to Rust or deprecate and remove it this can be updated in place to avoid the use of Python. API access from Python-space remains in terms of `DAGNode` instances to maintain API compatibility with the Python implementation. However, internally, we convert to and deal in terms of NodeType. When the user requests a particular node via lookup or iteration, we inflate an ephemeral `DAGNode` based on the internal `NodeType` and give them that. This is very similar to what was done in #10827 when porting CircuitData to Rust. As part of this porting there are a few small differences to keep in mind with the new Rust implementation of DAGCircuit. The first is that the topological ordering is slightly different with the new DAGCircuit. Previously, the Python version of `DAGCircuit` using a lexicographical topological sort key which was basically `"0,1,0,2"` where the first `0,1` are qargs on qubit indices `0,1` for nodes and `0,2` are cargs on clbit indices `0,2`. However, the sort key has now changed to be `(&[Qubit(0), Qubit(1)], &[Clbit(0), Clbit(2)])` in rust in this case which for the most part should behave identically, but there are some edge cases that will appear where the sort order is different. It will always be a valid topological ordering as the lexicographical key is used as a tie breaker when generating a topological sort. But if you're relaying on the exact same sort order there will be differences after this PR. The second is that a lot of undocumented functionality in the DAGCircuit which previously worked because of Python's implicit support for interacting with data structures is no longer functional. For example, previously the `DAGCircuit.qubits` list could be set directly (as the circuit visualizers previously did), but this was never documented as supported (and would corrupt the DAGCircuit). Any functionality like this we'd have to explicit include in the Rust implementation and as they were not included in the documented public API this PR opted to remove the vast majority of this type of functionality. The last related thing might require future work to mitigate is that this PR breaks the linkage between `DAGNode` and the underlying `DAGCirucit` object. In the Python implementation the `DAGNode` objects were stored directly in the `DAGCircuit` and when an API method returned a `DAGNode` from the DAG it was a shared reference to the underlying object in the `DAGCircuit`. This meant if you mutated the `DAGNode` it would be reflected in the `DAGCircuit`. This was not always a sound usage of the API as the `DAGCircuit` was implicitly caching many attributes of the DAG and you should always be using the `DAGCircuit` API to mutate any nodes to prevent any corruption of the `DAGCircuit`. However, now as the underlying data store for nodes in the DAG are no longer the python space objects returned by `DAGCircuit` methods mutating a `DAGNode` will not make any change in the underlying `DAGCircuit`. This can come as quite the surprise at first, especially if you were relying on this side effect, even if it was unsound. It's also worth noting that 2 large pieces of functionality from rustworkx are included in this PR. These are the new files `rustworkx_core_vnext` and `dot_utils` which are rustworkx's VF2 implementation and its dot file generation. As there was not a rust interface exposed for this functionality from rustworkx-core there was no way to use these functions in rustworkx. Until these interfaces added to rustworkx-core in future releases we'll have to keep these local copies. The vf2 implementation is in progress in Qiskit/rustworkx#1235, but `dot_utils` might make sense to keep around longer term as it is slightly modified from the upstream rustworkx implementation to directly interface with `DAGCircuit` instead of a generic graph. Co-authored-by: Matthew Treinish Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Alexander Ivrii Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Co-authored-by: John Lapeyre Co-authored-by: Jake Lishman * Update visual mpl circuit drawer references Right now there is a bug in the matplotlib circuit visualizer likely caused by the new `__eq__` implementation for `DAGOpNode` that didn't exist before were some gates are missing from the visualization. In the interest of unblocking this PR this commit updates the references for these cases temporarily until this issue is fixed. * Ensure DAGNode.sort_key is always a string Previously the sort_key attribute of the Python space DAGCircuit was incorrectly being set to `None` for rust generated node objects. This was done as for the default path the sort key is determined from the rust domain's representation of qubits and there is no analogous data in the Python object. However, this was indavertandly a breaking API change as sort_key is expected to always be a string. This commit adds a default string to use for all node types so that we always have a reasonable value that matches the typing of the class. A future step is likely to add back the `dag` kwarg to the node types and generate the string on the fly from the rust space data. * Make Python argument first in Param::eq and Param::is_close The standard function signature convention for functions that take a `py: Python` argument is to make the Python argument the first (or second after `&self`). The `Param::eq` and `Param::is_close` methods were not following this convention and had `py` as a later argument in the signature. This commit corrects the oversight. * Fix merge conflict with #12943 With the recent merge with main we pulled in #12943 which conflicted with the rust space API changes made in this PR branch. This commit updates the usage to conform with the new interface introduced in this PR. * Add release notes and test for invalid args on apply methods This commit adds several release notes to document this change. This includes a feature note to describe the high level change and the user facing benefit (mainly reduced memory consumption for DAGCircuits), two upgrade notes to document the differences with shared references caused by the new data structure, and a fix note documenting the fix for how qargs and cargs are handled on `.apply_operation_back()` and `.apply_operation_front()`. Along with the fix note a new unit test is added to serve as a regression test so that we don't accidentally allow adding cargs as qargs and vice versa in the future. * Restore `inplace` argument functionality for substitute_node() This commit restores the functionality of the `inplace` argument for `substitute_node()` and restores the tests validating the object identity when using the flag. This flag was originally excluded from the implementation because the Rust representation of the dag is not a shared reference with Python space and the flag doesn't really mean the same thing as there is always a second copy of the data for Python space now. The implementation here is cheating slighty as we're passed in the DAG node by reference it relies on that reference to update the input node at the same time we update the dag. Unlike the previous Python implementation where we were updating the node in place and the `inplace` argument was slightly faster because everything was done by reference. The rust space data is still a compressed copy of the data we return to Python so the `inplace` flag will be slightly more inefficient as we need to copy to update the Python space representation in addition to the rust version. * Revert needless dict() cast on metadata in dag_to_circuit() This commit removes an unecessary `dict()` cast on the `dag.metadata` when setting it on `QuantumCircuit.metadata` in `qiskit.converters.dag_to_circuit()`. This slipped in at some point during the development of this PR and it's not clear why, but it isn't needed so this removes it. * Add code comment for DAGOpNode.__eq__ parameter checking This commit adds a small inline code comment to make it clear why we skip parameter comparisons in DAGOpNode.__eq__ for python ops. It might not be clear why the value is hard coded to `true` in this case, as this check is done via Python so we don't need to duplicate it in rust space. * Raise a ValueError on DAGNode creation with invalid index This commit adds error checking to the DAGNode constructor to raise a PyValueError if the input index is not valid (any index < -1). Previously this would have panicked instead of raising a user catchable error. * Use macro argument to set python getter/setter name This commit updates the function names for `get__node_id` and `set__node_id` method to use a name that clippy is happy with and leverage the pyo3 macros to set the python space name correctly instead of using the implicit naming rules. * Remove Ord and PartialOrd derives from interner::Index The Ord and PartialOrd traits were originally added to the Index struct so they could be used for the sort key in lexicographical topological sorting. However, that approach was abandonded during the development of this PR and instead the expanded Qubit and Clbit indices were used instead. This left the ordering traits as unnecessary on Index and potentially misleading. This commit just opts to remove them as they're not needed anymore. * Fix missing nodes in matplotlib drawer. Previously, the change in equality for DAGNodes was causing nodes to clobber eachother in the matplotlib drawer's tracking data structures when used as keys to maps. To fix this, we ensure that all nodes have a unique ID across layers before constructing the matplotlib drawer. They actually of course _do_ in the original DAG, but we don't really care what the original IDs are, so we just make them up. Writing to _node_id on a DAGNode may seem odd, but it exists in the old Python API (prior to being ported to Rust) and doesn't actually mutate the DAG at all since DAGNodes are ephemeral. * Revert "Update visual mpl circuit drawer references" With the previous commit the bug in the matplotlib drawer causing the images to diverge should be fixed. This commit reverts the change to the reference images as there should be no difference now. This reverts commit 1e4e6f386286b0b4e7f3ebd3f706f948dd707575. * Update visual mpl circuit drawer references for control flow circuits The earlier commit that "fixed" the drawers corrected the visualization to match expectations in most cases. However after restoring the references to what's on main several comparison tests with control flow in the circuit were still failing. The failure mode looks similar to the other cases, but across control flow blocks instead of at the circuit level. This commit temporarily updates the references of these to the state of what is generated currently to unblock CI. If/when we have a fix this commit can be reverted. * Fix edge cases in DAGOpNode.__eq__ This commit fixes a couple of edge cases in DAGOpNode.__eq__ method around the python interaction for the method. The first is that in the case where we had python object parameter types for the gates we weren't comparing them at all. This is fixed so we use python object equality for the params in this case. Then we were dropping the error handling in the case of using python for equality, this fixes it to return the error to users if the equality check fails. Finally a comment is added to explain the expected use case for `DAGOpNode.__eq__` and why parameter checking is more strict than elsewhere. * Remove Param::add() for global phase addition This commit removes the Param::add() method and instead adds a local private function to the `dag_circuit` module for doing global phase addition. Previously the `Param::add()` method was used solely for adding global phase in `DAGCircuit` and it took some shortcuts knowing that context. This made the method implementation ill suited as a general implementation. * More complete fix for matplotlib drawer. * Revert "Update visual mpl circuit drawer references for control flow circuits" This reverts commit 9a6f9536a3a7412d19a9fd9bbd761825c9a53d0f. * Unify rayon versions in workspace * Remove unused _GLOBAL_NID. * Use global monotonic ID counter for ids in drawer The fundamental issue with matplotlib visualizations of control flow is that locally in the control flow block the nodes look the same but are stored in an outer circuit dictionary. If the gates are the same and on the same qubits and happen to have the same node id inside the different control flow blocks the drawer would think it's already drawn the node and skip it incorrectly. The previous fix for this didn't go far enough because it wasn't accounting for the recursive execution of the drawer for inner blocks (it also didn't account for LayerSpoolers of the same length). * Re-add missing documentation * Remove unused BitData iterator stuff. * Make types, dag, and bit count methods public This commit makes some attributes of the dag circuit public as they will need to be accessible from the accelerate crate to realistically start using the DAGCircuit for rust transpiler passes. * Make Wire pickle serialization explicit This commit pivots away from using the PyO3 crate's conversion traits for specialized pickle serialization output of Wire objects. The output of the previous traits wasn't really intended for representing a Wire in Python but only for pickle serialization. This commit migrates these to custom methods, without a trait, to make it clear they're only for pickle. * Make py token usage explicit in _VarIndexMap The _VarIndexMap type was designed to look like an IndexMap but is actually an inner python dictionary. This is because `Var` types are still defined in python and we need to use a dictionary if we have `Var` objects as keys in the mapping. In the interest of looking like an IndexMap all the methods (except for 1) used `with_gil` internally to work with the dictionary. This could add unecessary overhead and to make it explicit that there is python involvement with this struct's methods this commit adds a py: Python argument to all the methods and removes the `with_gil` usage. * Make all pub(crate) visibility pub * Remove unused method * Reorganize code structure around PyVariableMapper and BitLocations * Add missing var wires to .get_wires() method In the porting of the get_wires() method to Rust the handling of Var wires was missed in the output of the method. This commit corrects the oversight and adds them to the output. * Raise TypeError not ValueError for invalid input to set_global_phase * De-duplicate check logic for op node adding methods The methods for checking the input was valid on apply_operation_back, apply_operation_front, and _apply_op_node_back were all identical. This combines them into a single method to deduplicate the code. * Improve collect_1q_runs() filter function The filter function for collect_1q_runs() was needlessly building a matrix for all the standard gates when all we need to know in that case is whether the standard gate is parameterized or not. If it's not then we're guaranteed to have a matrix available. This commit updates the filter logic to account for this and improve it's throughput on standard gates. * Use swap_remove instead of shift_remove * Combine input and output maps into single mapping This commit combines the `DAGCircuit` `qubit_input_map` and `qubit_output_map` fields into a single `IndexMap` `qubit_io_map` (and the same for `clbit_input_map` and `clbit_output_map` going to `clbit_io_map`). That stores the input and output as 2 element array where the first element is the input node index and the second element is the output node index. This reduces the number of lookups we need to do in practice and also reduces the memory overhead of `DAGCircuit`. * Ensure we account for clbits in depth() short circuit check * Also account for Vars in DAGCircuit.width() The number of vars should be included in the return from the width() method. This was previously missing in the new implementation of this method. * Remove duplicated _get_node() method The `_get_node()` method was duplicated with the already public `node()` method. This commit removes the duplicate and updates it's only usage in the code base. * Handle Var wires in classical_predecessors This method was missing the handling for var wires, this commit corrects the oversight. * Remove stray comment * Use Operation::control_flow() instead of isinstance checking * Use &str for increment_op and decrement_op This commit reworks the interface for the increment_op and decrement_op methods to work by reference instead of passing owned String objects to the methods. Using owned String objects was resulting in unecessary allocations and extra overhead that could be avoided. There are still a few places we needed to copy strings to ensure we're not mutating things while we have references to nodes in the dag, typically only in the decrement/removal case. But this commit reduces the number of String copies we need to make in the DAGCircuit. * Also include vars in depth short circuit * Fix typing for controlflow name lookup in count_ops * Fix .properties() method to include operations field The .properties() method should have included the output of .count_ops() in its dictionary return but this was commented out temporarily while other pieces of this PR were fixed. This commit circles back to it and adds the missing field from the output. As an aside we should probably deprecate the .properties() method for removal in 2.0 it doesn't seem to be the most useful method in practice. * Add missing Var wire handling to py_nodes_on_wire * Add back optimization to avoid isinstance in op_nodes This commit adds back an optimization to the op_nodes dag method to avoid doing a python space op comparison when we're filtering on non-standard gates and evaluating a standard gate. In these cases we know that the filter will not match purely from rust without needing a python space op object creation or an isinstance call so we can avoid the overhead of doing that. * Simplify/deduplicate __eq__ method This commit reworks the logic in the DAGCircuit.__eq__ method implementation to simplify the code a bit and make it less verbose and duplicated. * Invalidate cached py op when needed in substitute_node_with_dag This commit fixes a potential issue in substitute_node_with_dag() when the propagate_condition flag was set we were not invalidating cached py ops when adding a new condition based on a propagated condition. This could potentially cause the incorrect object to be returned to Python after calling this method. This fixes the issues by clearing the cached node so that when returning the op to python we are regenerating the python object. * Copy-editing suggestions for release notes Co-authored-by: John Lapeyre * Fix and simplify separable_circuits() This commit fixes and simplifies the separable_circuits() method. At it's core the method is building a subgraph of the original dag for each weakly connected component in the dag with a little bit of extra tracking to make sure the graph is a valid DAGCircuit. Instead of trying to do this manually this commit updates the method implementation to leverage the tools petgraph gives us for filtering graphs. This both fixes a bug identified in review but also simplifies the code. * Add clbit removal test * Move to using a Vec<[NodeIndex; 2]> for io maps This commit migrates the qubit_io_map and clbit_io_map to go from a type of `IndexMap` to `Vec<[NodeIndex; 2]>`. Our qubit indices (represented by the `Qubit` type) must be a contiguous set for the circuit to be valid, and using an `IndexMap` for these mappings of bit to input and output nodes only really improved performance in the removal case, but at the cost of additional runtime overhead for accessing the data. Since removals are rare and also inefficient because it needs to reindex the entire dag already we should instead optimize for the accessing the data. Since we have contiguous indices using a Vec is a natural structure to represent this mapping. * Make add_clbits() signature the same as add_qubits() At some point during the development of this PR the function signatures between `add_qubits()` and `add_clbits()` diverged between taking a `Vec>` and `&Bound`. In general they're are comprable but since we are going to be working with a `Vec<>` in the function body this is a better choice to let PyO3 worry about the conversion for us. Additionally, this is a more natural signature for rust consumption. This commit just updates `add_clbits()` to use a Vec too. * Add attribution comment to num_tensor_factors() method * Add py argument to add_declared_var() * Remove unnecessarily Python-space check * Correct typo in `to_pickle` method --------- Co-authored-by: Matthew Treinish Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Alexander Ivrii Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Co-authored-by: John Lapeyre Co-authored-by: Jake Lishman --- Cargo.lock | 6 + Cargo.toml | 6 +- crates/accelerate/Cargo.toml | 8 +- .../accelerate/src/convert_2q_block_matrix.rs | 26 +- .../src/euler_one_qubit_decomposer.rs | 24 +- crates/circuit/Cargo.toml | 14 +- crates/circuit/src/bit_data.rs | 45 +- crates/circuit/src/circuit_data.rs | 62 +- crates/circuit/src/circuit_instruction.rs | 19 +- crates/circuit/src/dag_circuit.rs | 6196 +++++++++++++++++ crates/circuit/src/dag_node.rs | 373 +- crates/circuit/src/dot_utils.rs | 109 + crates/circuit/src/error.rs | 16 + crates/circuit/src/imports.rs | 28 + crates/circuit/src/interner.rs | 83 +- crates/circuit/src/lib.rs | 29 +- crates/circuit/src/operations.rs | 25 + crates/circuit/src/packed_instruction.rs | 132 +- crates/circuit/src/rustworkx_core_vnext.rs | 1417 ++++ qiskit/converters/circuit_to_dag.py | 5 +- qiskit/dagcircuit/dagcircuit.py | 2403 +------ qiskit/dagcircuit/dagnode.py | 65 - .../two_qubit/two_qubit_decompose.py | 5 +- .../passes/basis/basis_translator.py | 6 +- .../passes/basis/unroll_3q_or_more.py | 4 +- .../passes/basis/unroll_custom_definitions.py | 4 +- .../passes/calibration/rzx_templates.py | 22 +- .../transpiler/passes/layout/apply_layout.py | 2 +- .../transpiler/passes/layout/sabre_layout.py | 2 +- .../optimization/commutative_cancellation.py | 4 +- .../passes/optimization/consolidate_blocks.py | 6 +- .../optimization/optimize_1q_decomposition.py | 6 +- .../passes/optimization/optimize_annotated.py | 6 +- .../passes/optimization/split_2q_unitaries.py | 7 +- .../transpiler/passes/routing/sabre_swap.py | 4 +- .../passes/routing/stochastic_swap.py | 6 +- .../padding/dynamical_decoupling.py | 5 +- .../scheduling/scheduling/base_scheduler.py | 4 +- .../passes/scheduling/time_unit_conversion.py | 2 +- .../passes/synthesis/high_level_synthesis.py | 6 +- .../passes/synthesis/unitary_synthesis.py | 12 +- .../transpiler/passes/utils/control_flow.py | 6 +- .../transpiler/passes/utils/gate_direction.py | 6 +- .../passes/utils/merge_adjacent_barriers.py | 2 +- qiskit/visualization/circuit/_utils.py | 33 +- qiskit/visualization/dag_visualization.py | 104 +- .../notes/dag-oxide-60b3d7219cb21703.yaml | 49 + test/python/compiler/test_transpiler.py | 22 +- test/python/dagcircuit/test_dagcircuit.py | 146 +- test/python/transpiler/_dummy_passes.py | 12 +- .../transpiler/test_collect_multiq_blocks.py | 1 + test/python/visualization/test_utils.py | 122 +- 52 files changed, 8726 insertions(+), 2981 deletions(-) create mode 100644 crates/circuit/src/dag_circuit.rs create mode 100644 crates/circuit/src/dot_utils.rs create mode 100644 crates/circuit/src/error.rs create mode 100644 crates/circuit/src/rustworkx_core_vnext.rs create mode 100644 releasenotes/notes/dag-oxide-60b3d7219cb21703.yaml diff --git a/Cargo.lock b/Cargo.lock index 63e36f18645c..12daf2e6299e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1187,12 +1187,18 @@ dependencies = [ name = "qiskit-circuit" version = "1.3.0" dependencies = [ + "ahash 0.8.11", + "approx", "bytemuck", "hashbrown 0.14.5", + "indexmap", + "itertools 0.13.0", "ndarray", "num-complex", "numpy", "pyo3", + "rayon", + "rustworkx-core", "smallvec", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index f6141f787fdf..a35a87d4d3b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,14 +16,18 @@ license = "Apache-2.0" [workspace.dependencies] bytemuck = "1.17" indexmap.version = "2.4.0" -hashbrown.version = "0.14.0" +hashbrown.version = "0.14.5" num-bigint = "0.4" num-complex = "0.4" ndarray = "^0.15.6" numpy = "0.21.0" smallvec = "1.13" thiserror = "1.0" +rustworkx-core = "0.15" +approx = "0.5" +itertools = "0.13.0" ahash = "0.8.11" +rayon = "1.10" # Most of the crates don't need the feature `extension-module`, since only `qiskit-pyext` builds an # actual C extension (the feature disables linking in `libpython`, which is forbidden in Python diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index c93e81b14dee..838fc0153577 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -10,7 +10,7 @@ name = "qiskit_accelerate" doctest = false [dependencies] -rayon = "1.10" +rayon.workspace = true numpy.workspace = true rand = "0.8" rand_pcg = "0.3" @@ -18,10 +18,10 @@ rand_distr = "0.4.3" ahash.workspace = true num-traits = "0.2" num-complex.workspace = true +rustworkx-core.workspace = true num-bigint.workspace = true -rustworkx-core = "0.15" faer = "0.19.1" -itertools = "0.13.0" +itertools.workspace = true qiskit-circuit.workspace = true thiserror.workspace = true @@ -38,7 +38,7 @@ workspace = true features = ["rayon", "approx-0_5"] [dependencies.approx] -version = "0.5" +workspace = true features = ["num-complex"] [dependencies.hashbrown] diff --git a/crates/accelerate/src/convert_2q_block_matrix.rs b/crates/accelerate/src/convert_2q_block_matrix.rs index e9f6e343b6bd..dc4d0b77c4a7 100644 --- a/crates/accelerate/src/convert_2q_block_matrix.rs +++ b/crates/accelerate/src/convert_2q_block_matrix.rs @@ -27,7 +27,7 @@ use qiskit_circuit::circuit_instruction::CircuitInstruction; use qiskit_circuit::dag_node::DAGOpNode; use qiskit_circuit::gate_matrix::ONE_QUBIT_IDENTITY; use qiskit_circuit::imports::QI_OPERATOR; -use qiskit_circuit::operations::{Operation, OperationRef}; +use qiskit_circuit::operations::Operation; use crate::QiskitError; @@ -35,7 +35,7 @@ fn get_matrix_from_inst<'py>( py: Python<'py>, inst: &'py CircuitInstruction, ) -> PyResult> { - if let Some(mat) = inst.op().matrix(&inst.params) { + if let Some(mat) = inst.operation.matrix(&inst.params) { Ok(mat) } else if inst.operation.try_standard_gate().is_some() { Err(QiskitError::new_err( @@ -124,29 +124,7 @@ pub fn change_basis(matrix: ArrayView2) -> Array2 { trans_matrix } -#[pyfunction] -pub fn collect_2q_blocks_filter(node: &Bound) -> Option { - let Ok(node) = node.downcast::() else { - return None; - }; - let node = node.borrow(); - match node.instruction.op() { - gate @ (OperationRef::Standard(_) | OperationRef::Gate(_)) => Some( - gate.num_qubits() <= 2 - && node - .instruction - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - .is_none() - && !node.is_parameterized(), - ), - _ => Some(false), - } -} - pub fn convert_2q_block_matrix(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(blocks_to_matrix))?; - m.add_wrapped(wrap_pyfunction!(collect_2q_blocks_filter))?; Ok(()) } diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index 7463777af624..75a2f7993f86 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -743,7 +743,7 @@ pub fn compute_error_list( .iter() .map(|node| { ( - node.instruction.op().name().to_string(), + node.instruction.operation.name().to_string(), smallvec![], // Params not needed in this path ) }) @@ -988,10 +988,11 @@ pub fn optimize_1q_gates_decomposition( .iter() .map(|node| { if let Some(err_map) = error_map { - error *= compute_error_term(node.instruction.op().name(), err_map, qubit) + error *= + compute_error_term(node.instruction.operation.name(), err_map, qubit) } node.instruction - .op() + .operation .matrix(&node.instruction.params) .expect("No matrix defined for operation") }) @@ -1043,22 +1044,6 @@ fn matmul_1q(operator: &mut [[Complex64; 2]; 2], other: Array2) { ]; } -#[pyfunction] -pub fn collect_1q_runs_filter(node: &Bound) -> bool { - let Ok(node) = node.downcast::() else { - return false; - }; - let node = node.borrow(); - let op = node.instruction.op(); - op.num_qubits() == 1 - && op.num_clbits() == 0 - && op.matrix(&node.instruction.params).is_some() - && match &node.instruction.extra_attrs { - None => true, - Some(attrs) => attrs.condition.is_none(), - } -} - pub fn euler_one_qubit_decomposer(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(params_zyz))?; m.add_wrapped(wrap_pyfunction!(params_xyx))?; @@ -1072,7 +1057,6 @@ pub fn euler_one_qubit_decomposer(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(compute_error_one_qubit_sequence))?; m.add_wrapped(wrap_pyfunction!(compute_error_list))?; m.add_wrapped(wrap_pyfunction!(optimize_1q_gates_decomposition))?; - m.add_wrapped(wrap_pyfunction!(collect_1q_runs_filter))?; m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/crates/circuit/Cargo.toml b/crates/circuit/Cargo.toml index 3eb430515fcf..ed1f849bbf62 100644 --- a/crates/circuit/Cargo.toml +++ b/crates/circuit/Cargo.toml @@ -10,17 +10,29 @@ name = "qiskit_circuit" doctest = false [dependencies] +rayon.workspace = true +ahash.workspace = true +rustworkx-core.workspace = true bytemuck.workspace = true -hashbrown.workspace = true num-complex.workspace = true ndarray.workspace = true numpy.workspace = true thiserror.workspace = true +approx.workspace = true +itertools.workspace = true [dependencies.pyo3] workspace = true features = ["hashbrown", "indexmap", "num-complex", "num-bigint", "smallvec"] +[dependencies.hashbrown] +workspace = true +features = ["rayon"] + +[dependencies.indexmap] +workspace = true +features = ["rayon"] + [dependencies.smallvec] workspace = true features = ["union"] diff --git a/crates/circuit/src/bit_data.rs b/crates/circuit/src/bit_data.rs index 977d1b34e496..0c0b20a02522 100644 --- a/crates/circuit/src/bit_data.rs +++ b/crates/circuit/src/bit_data.rs @@ -81,17 +81,6 @@ pub struct BitData { cached: Py, } -pub struct BitNotFoundError<'py>(pub(crate) Bound<'py, PyAny>); - -impl<'py> From> for PyErr { - fn from(error: BitNotFoundError) -> Self { - PyKeyError::new_err(format!( - "Bit {:?} has not been added to this circuit.", - error.0 - )) - } -} - impl BitData where T: From + Copy, @@ -139,14 +128,19 @@ where pub fn map_bits<'py>( &self, bits: impl IntoIterator>, - ) -> Result, BitNotFoundError<'py>> { + ) -> PyResult> { let v: Result, _> = bits .into_iter() .map(|b| { self.indices .get(&BitAsKey::new(&b)) .copied() - .ok_or_else(|| BitNotFoundError(b)) + .ok_or_else(|| { + PyKeyError::new_err(format!( + "Bit {:?} has not been added to this circuit.", + b + )) + }) }) .collect(); v.map(|x| x.into_iter()) @@ -168,7 +162,7 @@ where } /// Adds a new Python bit. - pub fn add(&mut self, py: Python, bit: &Bound, strict: bool) -> PyResult<()> { + pub fn add(&mut self, py: Python, bit: &Bound, strict: bool) -> PyResult { if self.bits.len() != self.cached.bind(bit.py()).len() { return Err(PyRuntimeError::new_err( format!("This circuit's {} list has become out of sync with the circuit data. Did something modify it?", self.description) @@ -193,6 +187,29 @@ where bit ))); } + Ok(idx.into()) + } + + pub fn remove_indices(&mut self, py: Python, indices: I) -> PyResult<()> + where + I: IntoIterator, + { + let mut indices_sorted: Vec = indices + .into_iter() + .map(|i| >::from(i) as usize) + .collect(); + indices_sorted.sort(); + + for index in indices_sorted.into_iter().rev() { + self.cached.bind(py).del_item(index)?; + let bit = self.bits.remove(index); + self.indices.remove(&BitAsKey::new(bit.bind(py))); + } + // Update indices. + for (i, bit) in self.bits.iter().enumerate() { + self.indices + .insert(BitAsKey::new(bit.bind(py)), (i as BitType).into()); + } Ok(()) } diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index d29455c5363b..4dd3956bee6a 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -16,7 +16,7 @@ use std::cell::OnceCell; use crate::bit_data::BitData; use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; use crate::imports::{ANNOTATED_OPERATION, CLBIT, QUANTUM_CIRCUIT, QUBIT}; -use crate::interner::{IndexedInterner, Interner, InternerKey}; +use crate::interner::{IndexedInterner, Interner}; use crate::operations::{Operation, OperationRef, Param, StandardGate}; use crate::packed_instruction::{PackedInstruction, PackedOperation}; use crate::parameter_table::{ParameterTable, ParameterTableError, ParameterUse, ParameterUuid}; @@ -148,12 +148,8 @@ impl CircuitData { global_phase, )?; for (operation, params, qargs, cargs) in instruction_iter { - let qubits = (&mut res.qargs_interner) - .intern(InternerKey::Value(qargs))? - .index; - let clbits = (&mut res.cargs_interner) - .intern(InternerKey::Value(cargs))? - .index; + let qubits = (&mut res.qargs_interner).intern(qargs)?; + let clbits = (&mut res.cargs_interner).intern(cargs)?; let params = (!params.is_empty()).then(|| Box::new(params)); res.data.push(PackedInstruction { op: operation, @@ -203,13 +199,9 @@ impl CircuitData { instruction_iter.size_hint().0, global_phase, )?; - let no_clbit_index = (&mut res.cargs_interner) - .intern(InternerKey::Value(Vec::new()))? - .index; + let no_clbit_index = (&mut res.cargs_interner).intern(Vec::new())?; for (operation, params, qargs) in instruction_iter { - let qubits = (&mut res.qargs_interner) - .intern(InternerKey::Value(qargs.to_vec()))? - .index; + let qubits = (&mut res.qargs_interner).intern(qargs.to_vec())?; let params = (!params.is_empty()).then(|| Box::new(params)); res.data.push(PackedInstruction { op: operation.into(), @@ -266,13 +258,9 @@ impl CircuitData { params: &[Param], qargs: &[Qubit], ) -> PyResult<()> { - let no_clbit_index = (&mut self.cargs_interner) - .intern(InternerKey::Value(Vec::new()))? - .index; + let no_clbit_index = (&mut self.cargs_interner).intern(Vec::new())?; let params = (!params.is_empty()).then(|| Box::new(params.iter().cloned().collect())); - let qubits = (&mut self.qargs_interner) - .intern(InternerKey::Value(qargs.to_vec()))? - .index; + let qubits = (&mut self.qargs_interner).intern(qargs.to_vec())?; self.data.push(PackedInstruction { op: operation.into(), qubits, @@ -497,7 +485,8 @@ impl CircuitData { /// was provided. #[pyo3(signature = (bit, *, strict=true))] pub fn add_qubit(&mut self, py: Python, bit: &Bound, strict: bool) -> PyResult<()> { - self.qubits.add(py, bit, strict) + self.qubits.add(py, bit, strict)?; + Ok(()) } /// Registers a :class:`.Clbit` instance. @@ -511,7 +500,8 @@ impl CircuitData { /// was provided. #[pyo3(signature = (bit, *, strict=true))] pub fn add_clbit(&mut self, py: Python, bit: &Bound, strict: bool) -> PyResult<()> { - self.clbits.add(py, bit, strict) + self.clbits.add(py, bit, strict)?; + Ok(()) } /// Performs a shallow copy. @@ -582,10 +572,10 @@ impl CircuitData { let qubits = PySet::empty_bound(py)?; let clbits = PySet::empty_bound(py)?; for inst in self.data.iter() { - for b in self.qargs_interner.intern(inst.qubits).value.iter() { + for b in self.qargs_interner.intern(inst.qubits) { qubits.add(self.qubits.get(*b).unwrap().clone_ref(py))?; } - for b in self.cargs_interner.intern(inst.clbits).value.iter() { + for b in self.cargs_interner.intern(inst.clbits) { clbits.add(self.clbits.get(*b).unwrap().clone_ref(py))?; } } @@ -751,8 +741,8 @@ impl CircuitData { let clbits = self.cargs_interner.intern(inst.clbits); CircuitInstruction { operation: inst.op.clone(), - qubits: PyTuple::new_bound(py, self.qubits.map_indices(qubits.value)).unbind(), - clbits: PyTuple::new_bound(py, self.clbits.map_indices(clbits.value)).unbind(), + qubits: PyTuple::new_bound(py, self.qubits.map_indices(qubits)).unbind(), + clbits: PyTuple::new_bound(py, self.clbits.map_indices(clbits)).unbind(), params: inst.params_view().iter().cloned().collect(), extra_attrs: inst.extra_attrs.clone(), #[cfg(feature = "cache_pygates")] @@ -905,7 +895,6 @@ impl CircuitData { let qubits = other .qargs_interner .intern(inst.qubits) - .value .iter() .map(|b| { Ok(self @@ -917,7 +906,6 @@ impl CircuitData { let clbits = other .cargs_interner .intern(inst.clbits) - .value .iter() .map(|b| { Ok(self @@ -927,14 +915,12 @@ impl CircuitData { }) .collect::>>()?; let new_index = self.data.len(); - let qubits_id = - Interner::intern(&mut self.qargs_interner, InternerKey::Value(qubits))?; - let clbits_id = - Interner::intern(&mut self.cargs_interner, InternerKey::Value(clbits))?; + let qubits_id = Interner::intern(&mut self.qargs_interner, qubits)?; + let clbits_id = Interner::intern(&mut self.cargs_interner, clbits)?; self.data.push(PackedInstruction { op: inst.op.clone(), - qubits: qubits_id.index, - clbits: clbits_id.index, + qubits: qubits_id, + clbits: clbits_id, params: inst.params.clone(), extra_attrs: inst.extra_attrs.clone(), #[cfg(feature = "cache_pygates")] @@ -1106,7 +1092,7 @@ impl CircuitData { pub fn num_nonlocal_gates(&self) -> usize { self.data .iter() - .filter(|inst| inst.op().num_qubits() > 1 && !inst.op().directive()) + .filter(|inst| inst.op.num_qubits() > 1 && !inst.op.directive()) .count() } } @@ -1129,16 +1115,16 @@ impl CircuitData { fn pack(&mut self, py: Python, inst: &CircuitInstruction) -> PyResult { let qubits = Interner::intern( &mut self.qargs_interner, - InternerKey::Value(self.qubits.map_bits(inst.qubits.bind(py))?.collect()), + self.qubits.map_bits(inst.qubits.bind(py))?.collect(), )?; let clbits = Interner::intern( &mut self.cargs_interner, - InternerKey::Value(self.clbits.map_bits(inst.clbits.bind(py))?.collect()), + self.clbits.map_bits(inst.clbits.bind(py))?.collect(), )?; Ok(PackedInstruction { op: inst.operation.clone(), - qubits: qubits.index, - clbits: clbits.index, + qubits, + clbits, params: (!inst.params.is_empty()).then(|| Box::new(inst.params.clone())), extra_attrs: inst.extra_attrs.clone(), #[cfg(feature = "cache_pygates")] diff --git a/crates/circuit/src/circuit_instruction.rs b/crates/circuit/src/circuit_instruction.rs index ae649b5a8110..b0620d78fb75 100644 --- a/crates/circuit/src/circuit_instruction.rs +++ b/crates/circuit/src/circuit_instruction.rs @@ -114,11 +114,6 @@ pub struct CircuitInstruction { } impl CircuitInstruction { - /// View the operation in this `CircuitInstruction`. - pub fn op(&self) -> OperationRef { - self.operation.view() - } - /// Get the Python-space operation, ensuring that it is mutable from Python space (singleton /// gates might not necessarily satisfy this otherwise). /// @@ -135,6 +130,12 @@ impl CircuitInstruction { out.call_method0(intern!(py, "to_mutable")) } } + + pub fn condition(&self) -> Option<&PyObject> { + self.extra_attrs + .as_ref() + .and_then(|args| args.condition.as_ref()) + } } #[pymethods] @@ -230,7 +231,7 @@ impl CircuitInstruction { /// Returns the Instruction name corresponding to the op for this node #[getter] fn get_name(&self, py: Python) -> PyObject { - self.op().name().to_object(py) + self.operation.name().to_object(py) } #[getter] @@ -252,7 +253,7 @@ impl CircuitInstruction { } #[getter] - fn condition(&self, py: Python) -> Option { + fn get_condition(&self, py: Python) -> Option { self.extra_attrs .as_ref() .and_then(|attrs| attrs.condition.as_ref().map(|x| x.clone_ref(py))) @@ -292,13 +293,13 @@ impl CircuitInstruction { /// Is the :class:`.Operation` contained in this node a directive? pub fn is_directive(&self) -> bool { - self.op().directive() + self.operation.directive() } /// Is the :class:`.Operation` contained in this instruction a control-flow operation (i.e. an /// instance of :class:`.ControlFlowOp`)? pub fn is_control_flow(&self) -> bool { - self.op().control_flow() + self.operation.control_flow() } /// Does this instruction contain any :class:`.ParameterExpression` parameters? diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs new file mode 100644 index 000000000000..bb5fff5e343a --- /dev/null +++ b/crates/circuit/src/dag_circuit.rs @@ -0,0 +1,6196 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use std::hash::{Hash, Hasher}; + +use ahash::RandomState; + +use crate::bit_data::BitData; +use crate::circuit_instruction::{ + CircuitInstruction, ExtraInstructionAttributes, OperationFromPython, +}; +use crate::dag_node::{DAGInNode, DAGNode, DAGOpNode, DAGOutNode}; +use crate::dot_utils::build_dot; +use crate::error::DAGCircuitError; +use crate::imports; +use crate::interner::{IndexedInterner, Interner}; +use crate::operations::{Operation, OperationRef, Param, PyInstruction}; +use crate::packed_instruction::PackedInstruction; +use crate::rustworkx_core_vnext::isomorphism; +use crate::{BitType, Clbit, Qubit, TupleLikeArg}; + +use hashbrown::{HashMap, HashSet}; +use indexmap::IndexMap; +use itertools::Itertools; + +use pyo3::exceptions::{PyIndexError, PyRuntimeError, PyTypeError, PyValueError}; +use pyo3::intern; +use pyo3::prelude::*; +use pyo3::types::{ + IntoPyDict, PyDict, PyInt, PyIterator, PyList, PySequence, PySet, PyString, PyTuple, PyType, +}; + +use rustworkx_core::dag_algo::layers; +use rustworkx_core::err::ContractError; +use rustworkx_core::graph_ext::ContractNodesDirected; +use rustworkx_core::petgraph; +use rustworkx_core::petgraph::prelude::StableDiGraph; +use rustworkx_core::petgraph::prelude::*; +use rustworkx_core::petgraph::stable_graph::{EdgeReference, NodeIndex}; +use rustworkx_core::petgraph::unionfind::UnionFind; +use rustworkx_core::petgraph::visit::{ + EdgeIndexable, IntoEdgeReferences, IntoNodeReferences, NodeFiltered, NodeIndexable, +}; +use rustworkx_core::petgraph::Incoming; +use rustworkx_core::traversal::{ + ancestors as core_ancestors, bfs_successors as core_bfs_successors, + descendants as core_descendants, +}; + +use std::cmp::Ordering; +use std::collections::{BTreeMap, VecDeque}; +use std::convert::Infallible; +use std::f64::consts::PI; + +#[cfg(feature = "cache_pygates")] +use std::cell::OnceCell; + +static CONTROL_FLOW_OP_NAMES: [&str; 4] = ["for_loop", "while_loop", "if_else", "switch_case"]; +static SEMANTIC_EQ_SYMMETRIC: [&str; 4] = ["barrier", "swap", "break_loop", "continue_loop"]; + +#[derive(Clone, Debug)] +pub enum NodeType { + QubitIn(Qubit), + QubitOut(Qubit), + ClbitIn(Clbit), + ClbitOut(Clbit), + VarIn(PyObject), + VarOut(PyObject), + Operation(PackedInstruction), +} + +#[derive(Clone, Debug)] +pub enum Wire { + Qubit(Qubit), + Clbit(Clbit), + Var(PyObject), +} + +impl PartialEq for Wire { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Wire::Qubit(q1), Wire::Qubit(q2)) => q1 == q2, + (Wire::Clbit(c1), Wire::Clbit(c2)) => c1 == c2, + (Wire::Var(v1), Wire::Var(v2)) => { + v1.is(v2) || Python::with_gil(|py| v1.bind(py).eq(v2).unwrap()) + } + _ => false, + } + } +} + +impl Eq for Wire {} + +impl Hash for Wire { + fn hash(&self, state: &mut H) { + match self { + Self::Qubit(qubit) => qubit.hash(state), + Self::Clbit(clbit) => clbit.hash(state), + Self::Var(var) => Python::with_gil(|py| var.bind(py).hash().unwrap().hash(state)), + } + } +} + +impl Wire { + fn to_pickle(&self, py: Python) -> PyObject { + match self { + Self::Qubit(bit) => (0, bit.0.into_py(py)).into_py(py), + Self::Clbit(bit) => (1, bit.0.into_py(py)).into_py(py), + Self::Var(var) => (2, var.clone_ref(py)).into_py(py), + } + } + + fn from_pickle(b: &Bound) -> PyResult { + let tuple: Bound = b.extract()?; + let wire_type: usize = tuple.get_item(0)?.extract()?; + if wire_type == 0 { + Ok(Self::Qubit(Qubit(tuple.get_item(1)?.extract()?))) + } else if wire_type == 1 { + Ok(Self::Clbit(Clbit(tuple.get_item(1)?.extract()?))) + } else if wire_type == 2 { + Ok(Self::Var(tuple.get_item(1)?.unbind())) + } else { + Err(PyTypeError::new_err("Invalid wire type")) + } + } +} + +// TODO: Remove me. +// This is a temporary map type used to store a mapping of +// Var to NodeIndex to hold us over until Var is ported to +// Rust. Currently, we need this because PyObject cannot be +// used as the key to an IndexMap. +// +// Once we've got Var ported, Wire should also become Hash + Eq +// and we can consider combining input/output nodes maps. +#[derive(Clone, Debug)] +struct _VarIndexMap { + dict: Py, +} + +impl _VarIndexMap { + pub fn new(py: Python) -> Self { + Self { + dict: PyDict::new_bound(py).unbind(), + } + } + + pub fn keys(&self, py: Python) -> impl Iterator { + self.dict + .bind(py) + .keys() + .into_iter() + .map(|k| k.unbind()) + .collect::>() + .into_iter() + } + + pub fn contains_key(&self, py: Python, key: &PyObject) -> bool { + self.dict.bind(py).contains(key).unwrap() + } + + pub fn get(&self, py: Python, key: &PyObject) -> Option { + self.dict + .bind(py) + .get_item(key) + .unwrap() + .map(|v| NodeIndex::new(v.extract().unwrap())) + } + + pub fn insert(&mut self, py: Python, key: PyObject, value: NodeIndex) { + self.dict + .bind(py) + .set_item(key, value.index().into_py(py)) + .unwrap() + } + + pub fn remove(&mut self, py: Python, key: &PyObject) -> Option { + let bound_dict = self.dict.bind(py); + let res = bound_dict + .get_item(key.clone_ref(py)) + .unwrap() + .map(|v| NodeIndex::new(v.extract().unwrap())); + let _del_result = bound_dict.del_item(key); + res + } + pub fn values<'py>(&self, py: Python<'py>) -> impl Iterator + 'py { + let values = self.dict.bind(py).values(); + values.iter().map(|x| NodeIndex::new(x.extract().unwrap())) + } + + pub fn iter<'py>(&self, py: Python<'py>) -> impl Iterator + 'py { + self.dict + .bind(py) + .iter() + .map(|(var, index)| (var.unbind(), NodeIndex::new(index.extract().unwrap()))) + } +} + +/// Quantum circuit as a directed acyclic graph. +/// +/// There are 3 types of nodes in the graph: inputs, outputs, and operations. +/// The nodes are connected by directed edges that correspond to qubits and +/// bits. +#[pyclass(module = "qiskit._accelerate.circuit")] +#[derive(Clone, Debug)] +pub struct DAGCircuit { + /// Circuit name. Generally, this corresponds to the name + /// of the QuantumCircuit from which the DAG was generated. + #[pyo3(get, set)] + name: Option, + /// Circuit metadata + #[pyo3(get, set)] + metadata: Option, + + calibrations: HashMap>, + + pub dag: StableDiGraph, + + #[pyo3(get)] + qregs: Py, + #[pyo3(get)] + cregs: Py, + + /// The cache used to intern instruction qargs. + qargs_cache: IndexedInterner>, + /// The cache used to intern instruction cargs. + cargs_cache: IndexedInterner>, + /// Qubits registered in the circuit. + pub qubits: BitData, + /// Clbits registered in the circuit. + pub clbits: BitData, + /// Global phase. + global_phase: Param, + /// Duration. + #[pyo3(get, set)] + duration: Option, + /// Unit of duration. + #[pyo3(get, set)] + unit: String, + + // Note: these are tracked separately from `qubits` and `clbits` + // because it's not yet clear if the Rust concept of a native Qubit + // and Clbit should correspond directly to the numerical Python + // index that users see in the Python API. + /// The index locations of bits, and their positions within + /// registers. + qubit_locations: Py, + clbit_locations: Py, + + /// Map from qubit to input and output nodes of the graph. + qubit_io_map: Vec<[NodeIndex; 2]>, + + /// Map from clbit to input and output nodes of the graph. + clbit_io_map: Vec<[NodeIndex; 2]>, + + // TODO: use IndexMap once Var is ported to Rust + /// Map from var to input nodes of the graph. + var_input_map: _VarIndexMap, + /// Map from var to output nodes of the graph. + var_output_map: _VarIndexMap, + + /// Operation kind to count + op_names: IndexMap, + + // Python modules we need to frequently access (for now). + control_flow_module: PyControlFlowModule, + vars_info: HashMap, + vars_by_type: [Py; 3], +} + +#[derive(Clone, Debug)] +struct PyControlFlowModule { + condition_resources: Py, + node_resources: Py, +} + +#[derive(Clone, Debug)] +struct PyLegacyResources { + clbits: Py, + cregs: Py, +} + +impl PyControlFlowModule { + fn new(py: Python) -> PyResult { + let module = PyModule::import_bound(py, "qiskit.circuit.controlflow")?; + Ok(PyControlFlowModule { + condition_resources: module.getattr("condition_resources")?.unbind(), + node_resources: module.getattr("node_resources")?.unbind(), + }) + } + + fn condition_resources(&self, condition: &Bound) -> PyResult { + let res = self + .condition_resources + .bind(condition.py()) + .call1((condition,))?; + Ok(PyLegacyResources { + clbits: res.getattr("clbits")?.downcast_into_exact()?.unbind(), + cregs: res.getattr("cregs")?.downcast_into_exact()?.unbind(), + }) + } + + fn node_resources(&self, node: &Bound) -> PyResult { + let res = self.node_resources.bind(node.py()).call1((node,))?; + Ok(PyLegacyResources { + clbits: res.getattr("clbits")?.downcast_into_exact()?.unbind(), + cregs: res.getattr("cregs")?.downcast_into_exact()?.unbind(), + }) + } +} + +struct PyVariableMapper { + mapper: Py, +} + +impl PyVariableMapper { + fn new( + py: Python, + target_cregs: Bound, + bit_map: Option>, + var_map: Option>, + add_register: Option>, + ) -> PyResult { + let kwargs: HashMap<&str, Option>> = + HashMap::from_iter([("add_register", add_register)]); + Ok(PyVariableMapper { + mapper: imports::VARIABLE_MAPPER + .get_bound(py) + .call( + (target_cregs, bit_map, var_map), + Some(&kwargs.into_py_dict_bound(py)), + )? + .unbind(), + }) + } + + fn map_condition<'py>( + &self, + condition: &Bound<'py, PyAny>, + allow_reorder: bool, + ) -> PyResult> { + let py = condition.py(); + let kwargs: HashMap<&str, Py> = + HashMap::from_iter([("allow_reorder", allow_reorder.into_py(py))]); + self.mapper.bind(py).call_method( + intern!(py, "map_condition"), + (condition,), + Some(&kwargs.into_py_dict_bound(py)), + ) + } + + fn map_target<'py>(&self, target: &Bound<'py, PyAny>) -> PyResult> { + let py = target.py(); + self.mapper + .bind(py) + .call_method1(intern!(py, "map_target"), (target,)) + } +} + +impl IntoPy> for PyVariableMapper { + fn into_py(self, _py: Python<'_>) -> Py { + self.mapper + } +} + +#[pyfunction] +fn reject_new_register(reg: &Bound) -> PyResult<()> { + Err(DAGCircuitError::new_err(format!( + "No register with '{:?}' to map this expression onto.", + reg.getattr("bits")? + ))) +} + +#[pyclass(module = "qiskit._accelerate.circuit")] +#[derive(Clone, Debug)] +struct BitLocations { + #[pyo3(get)] + index: usize, + #[pyo3(get)] + registers: Py, +} + +#[derive(Copy, Clone, Debug)] +enum DAGVarType { + Input = 0, + Capture = 1, + Declare = 2, +} + +#[derive(Clone, Debug)] +struct DAGVarInfo { + var: PyObject, + type_: DAGVarType, + in_node: NodeIndex, + out_node: NodeIndex, +} + +#[pymethods] +impl DAGCircuit { + #[new] + pub fn new(py: Python<'_>) -> PyResult { + Ok(DAGCircuit { + name: None, + metadata: Some(PyDict::new_bound(py).unbind().into()), + calibrations: HashMap::new(), + dag: StableDiGraph::default(), + qregs: PyDict::new_bound(py).unbind(), + cregs: PyDict::new_bound(py).unbind(), + qargs_cache: IndexedInterner::new(), + cargs_cache: IndexedInterner::new(), + qubits: BitData::new(py, "qubits".to_string()), + clbits: BitData::new(py, "clbits".to_string()), + global_phase: Param::Float(0.), + duration: None, + unit: "dt".to_string(), + qubit_locations: PyDict::new_bound(py).unbind(), + clbit_locations: PyDict::new_bound(py).unbind(), + qubit_io_map: Vec::new(), + clbit_io_map: Vec::new(), + var_input_map: _VarIndexMap::new(py), + var_output_map: _VarIndexMap::new(py), + op_names: IndexMap::default(), + control_flow_module: PyControlFlowModule::new(py)?, + vars_info: HashMap::new(), + vars_by_type: [ + PySet::empty_bound(py)?.unbind(), + PySet::empty_bound(py)?.unbind(), + PySet::empty_bound(py)?.unbind(), + ], + }) + } + + #[getter] + fn input_map(&self, py: Python) -> PyResult> { + let out_dict = PyDict::new_bound(py); + for (qubit, indices) in self + .qubit_io_map + .iter() + .enumerate() + .map(|(idx, indices)| (Qubit(idx as u32), indices)) + { + out_dict.set_item( + self.qubits.get(qubit).unwrap().clone_ref(py), + self.get_node(py, indices[0])?, + )?; + } + for (clbit, indices) in self + .clbit_io_map + .iter() + .enumerate() + .map(|(idx, indices)| (Clbit(idx as u32), indices)) + { + out_dict.set_item( + self.clbits.get(clbit).unwrap().clone_ref(py), + self.get_node(py, indices[0])?, + )?; + } + for (var, index) in self.var_input_map.dict.bind(py).iter() { + out_dict.set_item( + var, + self.get_node(py, NodeIndex::new(index.extract::()?))?, + )?; + } + Ok(out_dict.unbind()) + } + + #[getter] + fn output_map(&self, py: Python) -> PyResult> { + let out_dict = PyDict::new_bound(py); + for (qubit, indices) in self + .qubit_io_map + .iter() + .enumerate() + .map(|(idx, indices)| (Qubit(idx as u32), indices)) + { + out_dict.set_item( + self.qubits.get(qubit).unwrap().clone_ref(py), + self.get_node(py, indices[1])?, + )?; + } + for (clbit, indices) in self + .clbit_io_map + .iter() + .enumerate() + .map(|(idx, indices)| (Clbit(idx as u32), indices)) + { + out_dict.set_item( + self.clbits.get(clbit).unwrap().clone_ref(py), + self.get_node(py, indices[1])?, + )?; + } + for (var, index) in self.var_output_map.dict.bind(py).iter() { + out_dict.set_item( + var, + self.get_node(py, NodeIndex::new(index.extract::()?))?, + )?; + } + Ok(out_dict.unbind()) + } + + fn __getstate__(&self, py: Python) -> PyResult> { + let out_dict = PyDict::new_bound(py); + out_dict.set_item("name", self.name.as_ref().map(|x| x.clone_ref(py)))?; + out_dict.set_item("metadata", self.metadata.as_ref().map(|x| x.clone_ref(py)))?; + out_dict.set_item("calibrations", self.calibrations.clone())?; + out_dict.set_item("qregs", self.qregs.clone_ref(py))?; + out_dict.set_item("cregs", self.cregs.clone_ref(py))?; + out_dict.set_item("global_phase", self.global_phase.clone())?; + out_dict.set_item( + "qubit_io_map", + self.qubit_io_map + .iter() + .enumerate() + .map(|(k, v)| (k, [v[0].index(), v[1].index()])) + .collect::>(), + )?; + out_dict.set_item( + "clbit_io_map", + self.clbit_io_map + .iter() + .enumerate() + .map(|(k, v)| (k, [v[0].index(), v[1].index()])) + .collect::>(), + )?; + out_dict.set_item("var_input_map", self.var_input_map.dict.clone_ref(py))?; + out_dict.set_item("var_output_map", self.var_output_map.dict.clone_ref(py))?; + out_dict.set_item("op_name", self.op_names.clone())?; + out_dict.set_item( + "vars_info", + self.vars_info + .iter() + .map(|(k, v)| { + ( + k, + ( + v.var.clone_ref(py), + v.type_ as u8, + v.in_node.index(), + v.out_node.index(), + ), + ) + }) + .collect::>(), + )?; + out_dict.set_item("vars_by_type", self.vars_by_type.clone())?; + out_dict.set_item("qubits", self.qubits.bits())?; + out_dict.set_item("clbits", self.clbits.bits())?; + let mut nodes: Vec = Vec::with_capacity(self.dag.node_count()); + for node_idx in self.dag.node_indices() { + let node_data = self.get_node(py, node_idx)?; + nodes.push((node_idx.index(), node_data).to_object(py)); + } + out_dict.set_item("nodes", nodes)?; + out_dict.set_item( + "nodes_removed", + self.dag.node_count() != self.dag.node_bound(), + )?; + let mut edges: Vec = Vec::with_capacity(self.dag.edge_bound()); + // edges are saved with none (deleted edges) instead of their index to save space + for i in 0..self.dag.edge_bound() { + let idx = EdgeIndex::new(i); + let edge = match self.dag.edge_weight(idx) { + Some(edge_w) => { + let endpoints = self.dag.edge_endpoints(idx).unwrap(); + ( + endpoints.0.index(), + endpoints.1.index(), + edge_w.clone().to_pickle(py), + ) + .to_object(py) + } + None => py.None(), + }; + edges.push(edge); + } + out_dict.set_item("edges", edges)?; + Ok(out_dict.unbind()) + } + + fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { + let dict_state = state.downcast_bound::(py)?; + self.name = dict_state.get_item("name")?.unwrap().extract()?; + self.metadata = dict_state.get_item("metadata")?.unwrap().extract()?; + self.calibrations = dict_state.get_item("calibrations")?.unwrap().extract()?; + self.qregs = dict_state.get_item("qregs")?.unwrap().extract()?; + self.cregs = dict_state.get_item("cregs")?.unwrap().extract()?; + self.global_phase = dict_state.get_item("global_phase")?.unwrap().extract()?; + self.op_names = dict_state.get_item("op_name")?.unwrap().extract()?; + self.var_input_map = _VarIndexMap { + dict: dict_state.get_item("var_input_map")?.unwrap().extract()?, + }; + self.var_output_map = _VarIndexMap { + dict: dict_state.get_item("var_output_map")?.unwrap().extract()?, + }; + self.vars_by_type = dict_state.get_item("vars_by_type")?.unwrap().extract()?; + let binding = dict_state.get_item("vars_info")?.unwrap(); + let vars_info_raw = binding.downcast::().unwrap(); + self.vars_info = HashMap::with_capacity(vars_info_raw.len()); + for (key, value) in vars_info_raw.iter() { + let val_tuple = value.downcast::()?; + let info = DAGVarInfo { + var: val_tuple.get_item(0)?.unbind(), + type_: match val_tuple.get_item(1)?.extract::()? { + 0 => DAGVarType::Input, + 1 => DAGVarType::Capture, + 2 => DAGVarType::Declare, + _ => return Err(PyValueError::new_err("Invalid var type")), + }, + in_node: NodeIndex::new(val_tuple.get_item(2)?.extract()?), + out_node: NodeIndex::new(val_tuple.get_item(3)?.extract()?), + }; + self.vars_info.insert(key.extract()?, info); + } + + let binding = dict_state.get_item("qubits")?.unwrap(); + let qubits_raw = binding.downcast::().unwrap(); + for bit in qubits_raw.iter() { + self.qubits.add(py, &bit, false)?; + } + let binding = dict_state.get_item("clbits")?.unwrap(); + let clbits_raw = binding.downcast::().unwrap(); + for bit in clbits_raw.iter() { + self.clbits.add(py, &bit, false)?; + } + let binding = dict_state.get_item("qubit_io_map")?.unwrap(); + let qubit_index_map_raw = binding.downcast::().unwrap(); + self.qubit_io_map = Vec::with_capacity(qubit_index_map_raw.len()); + for (_k, v) in qubit_index_map_raw.iter() { + let indices: [usize; 2] = v.extract()?; + self.qubit_io_map + .push([NodeIndex::new(indices[0]), NodeIndex::new(indices[1])]); + } + let binding = dict_state.get_item("clbit_io_map")?.unwrap(); + let clbit_index_map_raw = binding.downcast::().unwrap(); + self.clbit_io_map = Vec::with_capacity(clbit_index_map_raw.len()); + + for (_k, v) in clbit_index_map_raw.iter() { + let indices: [usize; 2] = v.extract()?; + self.clbit_io_map + .push([NodeIndex::new(indices[0]), NodeIndex::new(indices[1])]); + } + // Rebuild Graph preserving index holes: + let binding = dict_state.get_item("nodes")?.unwrap(); + let nodes_lst = binding.downcast::()?; + let binding = dict_state.get_item("edges")?.unwrap(); + let edges_lst = binding.downcast::()?; + let node_removed: bool = dict_state.get_item("nodes_removed")?.unwrap().extract()?; + self.dag = StableDiGraph::default(); + if !node_removed { + for item in nodes_lst.iter() { + let node_w = item.downcast::().unwrap().get_item(1).unwrap(); + let weight = self.pack_into(py, &node_w)?; + self.dag.add_node(weight); + } + } else if nodes_lst.len() == 1 { + // graph has only one node, handle logic here to save one if in the loop later + let binding = nodes_lst.get_item(0).unwrap(); + let item = binding.downcast::().unwrap(); + let node_idx: usize = item.get_item(0).unwrap().extract().unwrap(); + let node_w = item.get_item(1).unwrap(); + + for _i in 0..node_idx { + self.dag.add_node(NodeType::QubitIn(Qubit(u32::MAX))); + } + let weight = self.pack_into(py, &node_w)?; + self.dag.add_node(weight); + for i in 0..node_idx { + self.dag.remove_node(NodeIndex::new(i)); + } + } else { + let binding = nodes_lst.get_item(nodes_lst.len() - 1).unwrap(); + let last_item = binding.downcast::().unwrap(); + + // list of temporary nodes that will be removed later to re-create holes + let node_bound_1: usize = last_item.get_item(0).unwrap().extract().unwrap(); + let mut tmp_nodes: Vec = + Vec::with_capacity(node_bound_1 + 1 - nodes_lst.len()); + + for item in nodes_lst { + let item = item.downcast::().unwrap(); + let next_index: usize = item.get_item(0).unwrap().extract().unwrap(); + let weight: PyObject = item.get_item(1).unwrap().extract().unwrap(); + while next_index > self.dag.node_bound() { + // node does not exist + let tmp_node = self.dag.add_node(NodeType::QubitIn(Qubit(u32::MAX))); + tmp_nodes.push(tmp_node); + } + // add node to the graph, and update the next available node index + let weight = self.pack_into(py, weight.bind(py))?; + self.dag.add_node(weight); + } + // Remove any temporary nodes we added + for tmp_node in tmp_nodes { + self.dag.remove_node(tmp_node); + } + } + + // to ensure O(1) on edge deletion, use a temporary node to store missing edges + let tmp_node = self.dag.add_node(NodeType::QubitIn(Qubit(u32::MAX))); + + for item in edges_lst { + if item.is_none() { + // add a temporary edge that will be deleted later to re-create the hole + self.dag + .add_edge(tmp_node, tmp_node, Wire::Qubit(Qubit(u32::MAX))); + } else { + let triple = item.downcast::().unwrap(); + let edge_p: usize = triple.get_item(0).unwrap().extract().unwrap(); + let edge_c: usize = triple.get_item(1).unwrap().extract().unwrap(); + let edge_w = Wire::from_pickle(&triple.get_item(2).unwrap())?; + self.dag + .add_edge(NodeIndex::new(edge_p), NodeIndex::new(edge_c), edge_w); + } + } + self.dag.remove_node(tmp_node); + Ok(()) + } + + /// Returns the current sequence of registered :class:`.Qubit` instances as a list. + /// + /// .. warning:: + /// + /// Do not modify this list yourself. It will invalidate the :class:`DAGCircuit` data + /// structures. + /// + /// Returns: + /// list(:class:`.Qubit`): The current sequence of registered qubits. + #[getter] + pub fn qubits(&self, py: Python<'_>) -> Py { + self.qubits.cached().clone_ref(py) + } + + /// Returns the current sequence of registered :class:`.Clbit` + /// instances as a list. + /// + /// .. warning:: + /// + /// Do not modify this list yourself. It will invalidate the :class:`DAGCircuit` data + /// structures. + /// + /// Returns: + /// list(:class:`.Clbit`): The current sequence of registered clbits. + #[getter] + pub fn clbits(&self, py: Python<'_>) -> Py { + self.clbits.cached().clone_ref(py) + } + + /// Return a list of the wires in order. + #[getter] + fn get_wires(&self, py: Python<'_>) -> PyResult> { + let wires: Vec<&PyObject> = self + .qubits + .bits() + .iter() + .chain(self.clbits.bits().iter()) + .collect(); + let out_list = PyList::new_bound(py, wires); + for var_type_set in &self.vars_by_type { + for var in var_type_set.bind(py).iter() { + out_list.append(var)?; + } + } + Ok(out_list.unbind()) + } + + /// Returns the number of nodes in the dag. + #[getter] + fn get_node_counter(&self) -> usize { + self.dag.node_count() + } + + /// Return the global phase of the circuit. + #[getter] + fn get_global_phase(&self) -> Param { + self.global_phase.clone() + } + + /// Set the global phase of the circuit. + /// + /// Args: + /// angle (float, :class:`.ParameterExpression`): The phase angle. + #[setter] + fn set_global_phase(&mut self, angle: Param) -> PyResult<()> { + match angle { + Param::Float(angle) => { + self.global_phase = Param::Float(angle.rem_euclid(2. * PI)); + } + Param::ParameterExpression(angle) => { + self.global_phase = Param::ParameterExpression(angle); + } + Param::Obj(_) => return Err(PyTypeError::new_err("Invalid type for global phase")), + } + Ok(()) + } + + /// Return calibration dictionary. + /// + /// The custom pulse definition of a given gate is of the form + /// {'gate_name': {(qubits, params): schedule}} + #[getter] + fn get_calibrations(&self) -> HashMap> { + self.calibrations.clone() + } + + /// Set the circuit calibration data from a dictionary of calibration definition. + /// + /// Args: + /// calibrations (dict): A dictionary of input in the format + /// {'gate_name': {(qubits, gate_params): schedule}} + #[setter] + fn set_calibrations(&mut self, calibrations: HashMap>) { + self.calibrations = calibrations; + } + + /// Register a low-level, custom pulse definition for the given gate. + /// + /// Args: + /// gate (Union[Gate, str]): Gate information. + /// qubits (Union[int, Tuple[int]]): List of qubits to be measured. + /// schedule (Schedule): Schedule information. + /// params (Optional[List[Union[float, Parameter]]]): A list of parameters. + /// + /// Raises: + /// Exception: if the gate is of type string and params is None. + fn add_calibration<'py>( + &mut self, + py: Python<'py>, + mut gate: Bound<'py, PyAny>, + qubits: Bound<'py, PyAny>, + schedule: Py, + mut params: Option>, + ) -> PyResult<()> { + if gate.is_instance(imports::GATE.get_bound(py))? { + params = Some(gate.getattr(intern!(py, "params"))?); + gate = gate.getattr(intern!(py, "name"))?; + } + + let params_tuple = if let Some(operands) = params { + let add_calibration = PyModule::from_code_bound( + py, + r#" +import numpy as np + +def _format(operand): + try: + # Using float/complex value as a dict key is not good idea. + # This makes the mapping quite sensitive to the rounding error. + # However, the mechanism is already tied to the execution model (i.e. pulse gate) + # and we cannot easily update this rule. + # The same logic exists in QuantumCircuit.add_calibration. + evaluated = complex(operand) + if np.isreal(evaluated): + evaluated = float(evaluated.real) + if evaluated.is_integer(): + evaluated = int(evaluated) + return evaluated + except TypeError: + # Unassigned parameter + return operand + "#, + "add_calibration.py", + "add_calibration", + )?; + + let format = add_calibration.getattr("_format")?; + let mapped: PyResult> = operands.iter()?.map(|p| format.call1((p?,))).collect(); + PyTuple::new_bound(py, mapped?).into_any() + } else { + PyTuple::empty_bound(py).into_any() + }; + + let calibrations = self + .calibrations + .entry(gate.extract()?) + .or_insert_with(|| PyDict::new_bound(py).unbind()) + .bind(py); + + let qubits = if let Ok(qubits) = qubits.downcast::() { + qubits.to_tuple()?.into_any() + } else { + PyTuple::new_bound(py, [qubits]).into_any() + }; + let key = PyTuple::new_bound(py, &[qubits.unbind(), params_tuple.into_any().unbind()]); + calibrations.set_item(key, schedule)?; + Ok(()) + } + + /// Return True if the dag has a calibration defined for the node operation. In this + /// case, the operation does not need to be translated to the device basis. + fn has_calibration_for(&self, py: Python, node: PyRef) -> PyResult { + if !self + .calibrations + .contains_key(node.instruction.operation.name()) + { + return Ok(false); + } + let mut params = Vec::new(); + for p in &node.instruction.params { + if let Param::ParameterExpression(exp) = p { + let exp = exp.bind(py); + if !exp.getattr(intern!(py, "parameters"))?.is_truthy()? { + let as_py_float = exp.call_method0(intern!(py, "__float__"))?; + params.push(as_py_float.unbind()); + continue; + } + } + params.push(p.to_object(py)); + } + let qubits: Vec = self + .qubits + .map_bits(node.instruction.qubits.bind(py).iter())? + .map(|bit| bit.0) + .collect(); + let qubits = PyTuple::new_bound(py, qubits); + let params = PyTuple::new_bound(py, params); + self.calibrations[node.instruction.operation.name()] + .bind(py) + .contains((qubits, params).to_object(py)) + } + + /// Remove all operation nodes with the given name. + fn remove_all_ops_named(&mut self, opname: &str) { + let mut to_remove = Vec::new(); + for (id, weight) in self.dag.node_references() { + if let NodeType::Operation(packed) = &weight { + if opname == packed.op.name() { + to_remove.push(id); + } + } + } + for node in to_remove { + self.remove_op_node(node); + } + } + + /// Add individual qubit wires. + fn add_qubits(&mut self, py: Python, qubits: Vec>) -> PyResult<()> { + for bit in qubits.iter() { + if !bit.is_instance(imports::QUBIT.get_bound(py))? { + return Err(DAGCircuitError::new_err("not a Qubit instance.")); + } + + if self.qubits.find(bit).is_some() { + return Err(DAGCircuitError::new_err(format!( + "duplicate qubits {}", + bit + ))); + } + } + + for bit in qubits.iter() { + self.add_qubit_unchecked(py, bit)?; + } + Ok(()) + } + + /// Add individual qubit wires. + fn add_clbits(&mut self, py: Python, clbits: Vec>) -> PyResult<()> { + for bit in clbits.iter() { + if !bit.is_instance(imports::CLBIT.get_bound(py))? { + return Err(DAGCircuitError::new_err("not a Clbit instance.")); + } + + if self.clbits.find(bit).is_some() { + return Err(DAGCircuitError::new_err(format!( + "duplicate clbits {}", + bit + ))); + } + } + + for bit in clbits.iter() { + self.add_clbit_unchecked(py, bit)?; + } + Ok(()) + } + + /// Add all wires in a quantum register. + fn add_qreg(&mut self, py: Python, qreg: &Bound) -> PyResult<()> { + if !qreg.is_instance(imports::QUANTUM_REGISTER.get_bound(py))? { + return Err(DAGCircuitError::new_err("not a QuantumRegister instance.")); + } + + let register_name = qreg.getattr(intern!(py, "name"))?; + if self.qregs.bind(py).contains(®ister_name)? { + return Err(DAGCircuitError::new_err(format!( + "duplicate register {}", + register_name + ))); + } + self.qregs.bind(py).set_item(®ister_name, qreg)?; + + for (index, bit) in qreg.iter()?.enumerate() { + let bit = bit?; + if self.qubits.find(&bit).is_none() { + self.add_qubit_unchecked(py, &bit)?; + } + let locations: PyRef = self + .qubit_locations + .bind(py) + .get_item(&bit)? + .unwrap() + .extract()?; + locations.registers.bind(py).append((qreg, index))?; + } + Ok(()) + } + + /// Add all wires in a classical register. + fn add_creg(&mut self, py: Python, creg: &Bound) -> PyResult<()> { + if !creg.is_instance(imports::CLASSICAL_REGISTER.get_bound(py))? { + return Err(DAGCircuitError::new_err( + "not a ClassicalRegister instance.", + )); + } + + let register_name = creg.getattr(intern!(py, "name"))?; + if self.cregs.bind(py).contains(®ister_name)? { + return Err(DAGCircuitError::new_err(format!( + "duplicate register {}", + register_name + ))); + } + self.cregs.bind(py).set_item(register_name, creg)?; + + for (index, bit) in creg.iter()?.enumerate() { + let bit = bit?; + if self.clbits.find(&bit).is_none() { + self.add_clbit_unchecked(py, &bit)?; + } + let locations: PyRef = self + .clbit_locations + .bind(py) + .get_item(&bit)? + .unwrap() + .extract()?; + locations.registers.bind(py).append((creg, index))?; + } + Ok(()) + } + + /// Finds locations in the circuit, by mapping the Qubit and Clbit to positional index + /// BitLocations is defined as: BitLocations = namedtuple("BitLocations", ("index", "registers")) + /// + /// Args: + /// bit (Bit): The bit to locate. + /// + /// Returns: + /// namedtuple(int, List[Tuple(Register, int)]): A 2-tuple. The first element (``index``) + /// contains the index at which the ``Bit`` can be found (in either + /// :obj:`~DAGCircuit.qubits`, :obj:`~DAGCircuit.clbits`, depending on its + /// type). The second element (``registers``) is a list of ``(register, index)`` + /// pairs with an entry for each :obj:`~Register` in the circuit which contains the + /// :obj:`~Bit` (and the index in the :obj:`~Register` at which it can be found). + /// + /// Raises: + /// DAGCircuitError: If the supplied :obj:`~Bit` was of an unknown type. + /// DAGCircuitError: If the supplied :obj:`~Bit` could not be found on the circuit. + fn find_bit<'py>(&self, py: Python<'py>, bit: &Bound) -> PyResult> { + if bit.is_instance(imports::QUBIT.get_bound(py))? { + return self.qubit_locations.bind(py).get_item(bit)?.ok_or_else(|| { + DAGCircuitError::new_err(format!( + "Could not locate provided bit: {}. Has it been added to the DAGCircuit?", + bit + )) + }); + } + + if bit.is_instance(imports::CLBIT.get_bound(py))? { + return self.clbit_locations.bind(py).get_item(bit)?.ok_or_else(|| { + DAGCircuitError::new_err(format!( + "Could not locate provided bit: {}. Has it been added to the DAGCircuit?", + bit + )) + }); + } + + Err(DAGCircuitError::new_err(format!( + "Could not locate bit of unknown type: {}", + bit.get_type() + ))) + } + + /// Remove classical bits from the circuit. All bits MUST be idle. + /// Any registers with references to at least one of the specified bits will + /// also be removed. + /// + /// .. warning:: + /// This method is rather slow, since it must iterate over the entire + /// DAG to fix-up bit indices. + /// + /// Args: + /// clbits (List[Clbit]): The bits to remove. + /// + /// Raises: + /// DAGCircuitError: a clbit is not a :obj:`.Clbit`, is not in the circuit, + /// or is not idle. + #[pyo3(signature = (*clbits))] + fn remove_clbits(&mut self, py: Python, clbits: &Bound) -> PyResult<()> { + let mut non_bits = Vec::new(); + for bit in clbits.iter() { + if !bit.is_instance(imports::CLBIT.get_bound(py))? { + non_bits.push(bit); + } + } + if !non_bits.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "clbits not of type Clbit: {:?}", + non_bits + ))); + } + + let bit_iter = match self.clbits.map_bits(clbits.iter()) { + Ok(bit_iter) => bit_iter, + Err(_) => { + return Err(DAGCircuitError::new_err(format!( + "clbits not in circuit: {:?}", + clbits + ))) + } + }; + let clbits: HashSet = bit_iter.collect(); + let mut busy_bits = Vec::new(); + for bit in clbits.iter() { + if !self.is_wire_idle(py, &Wire::Clbit(*bit))? { + busy_bits.push(self.clbits.get(*bit).unwrap()); + } + } + + if !busy_bits.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "clbits not idle: {:?}", + busy_bits + ))); + } + + // Remove any references to bits. + let mut cregs_to_remove = Vec::new(); + for creg in self.cregs.bind(py).values() { + for bit in creg.iter()? { + let bit = bit?; + if clbits.contains(&self.clbits.find(&bit).unwrap()) { + cregs_to_remove.push(creg); + break; + } + } + } + self.remove_cregs(py, &PyTuple::new_bound(py, cregs_to_remove))?; + + // Remove DAG in/out nodes etc. + for bit in clbits.iter() { + self.remove_idle_wire(py, Wire::Clbit(*bit))?; + } + + // Copy the current clbit mapping so we can use it while remapping + // wires used on edges and in operation cargs. + let old_clbits = self.clbits.clone(); + + // Remove the clbit indices, which will invalidate our mapping of Clbit to + // Python bits throughout the entire DAG. + self.clbits.remove_indices(py, clbits.clone())?; + + // Update input/output maps to use new Clbits. + let io_mapping: HashMap = self + .clbit_io_map + .drain(..) + .enumerate() + .filter_map(|(k, v)| { + let clbit = Clbit(k as u32); + if clbits.contains(&clbit) { + None + } else { + Some(( + self.clbits + .find(old_clbits.get(Clbit(k as u32)).unwrap().bind(py)) + .unwrap(), + v, + )) + } + }) + .collect(); + + self.clbit_io_map = (0..io_mapping.len()) + .map(|idx| { + let clbit = Clbit(idx as u32); + io_mapping[&clbit] + }) + .collect(); + + // Update edges to use the new Clbits. + for edge_weight in self.dag.edge_weights_mut() { + if let Wire::Clbit(c) = edge_weight { + *c = self + .clbits + .find(old_clbits.get(*c).unwrap().bind(py)) + .unwrap(); + } + } + + // Update operation cargs to use the new Clbits. + for node_weight in self.dag.node_weights_mut() { + match node_weight { + NodeType::Operation(op) => { + let cargs = self.cargs_cache.intern(op.clbits); + let carg_bits = old_clbits + .map_indices(&cargs[..]) + .map(|b| b.bind(py).clone()); + let mapped_cargs = self.clbits.map_bits(carg_bits)?.collect(); + let clbits = Interner::intern(&mut self.cargs_cache, mapped_cargs)?; + op.clbits = clbits; + } + NodeType::ClbitIn(c) | NodeType::ClbitOut(c) => { + *c = self + .clbits + .find(old_clbits.get(*c).unwrap().bind(py)) + .unwrap(); + } + _ => (), + } + } + + // Update bit locations. + let bit_locations = self.clbit_locations.bind(py); + for (i, bit) in self.clbits.bits().iter().enumerate() { + let raw_loc = bit_locations.get_item(bit)?.unwrap(); + let loc = raw_loc.downcast::().unwrap(); + loc.borrow_mut().index = i; + bit_locations.set_item(bit, loc)?; + } + Ok(()) + } + + /// Remove classical registers from the circuit, leaving underlying bits + /// in place. + /// + /// Raises: + /// DAGCircuitError: a creg is not a ClassicalRegister, or is not in + /// the circuit. + #[pyo3(signature = (*cregs))] + fn remove_cregs(&mut self, py: Python, cregs: &Bound) -> PyResult<()> { + let mut non_regs = Vec::new(); + let mut unknown_regs = Vec::new(); + let self_bound_cregs = self.cregs.bind(py); + for reg in cregs.iter() { + if !reg.is_instance(imports::CLASSICAL_REGISTER.get_bound(py))? { + non_regs.push(reg); + } else if let Some(existing_creg) = + self_bound_cregs.get_item(®.getattr(intern!(py, "name"))?)? + { + if !existing_creg.eq(®)? { + unknown_regs.push(reg); + } + } else { + unknown_regs.push(reg); + } + } + if !non_regs.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "cregs not of type ClassicalRegister: {:?}", + non_regs + ))); + } + if !unknown_regs.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "cregs not in circuit: {:?}", + unknown_regs + ))); + } + + for creg in cregs { + self.cregs + .bind(py) + .del_item(creg.getattr(intern!(py, "name"))?)?; + for (i, bit) in creg.iter()?.enumerate() { + let bit = bit?; + let bit_position = self + .clbit_locations + .bind(py) + .get_item(bit)? + .unwrap() + .downcast_into_exact::()?; + bit_position + .borrow() + .registers + .bind(py) + .as_any() + .call_method1(intern!(py, "remove"), ((&creg, i),))?; + } + } + Ok(()) + } + + /// Remove quantum bits from the circuit. All bits MUST be idle. + /// Any registers with references to at least one of the specified bits will + /// also be removed. + /// + /// .. warning:: + /// This method is rather slow, since it must iterate over the entire + /// DAG to fix-up bit indices. + /// + /// Args: + /// qubits (List[~qiskit.circuit.Qubit]): The bits to remove. + /// + /// Raises: + /// DAGCircuitError: a qubit is not a :obj:`~.circuit.Qubit`, is not in the circuit, + /// or is not idle. + #[pyo3(signature = (*qubits))] + fn remove_qubits(&mut self, py: Python, qubits: &Bound) -> PyResult<()> { + let mut non_qbits = Vec::new(); + for bit in qubits.iter() { + if !bit.is_instance(imports::QUBIT.get_bound(py))? { + non_qbits.push(bit); + } + } + if !non_qbits.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "qubits not of type Qubit: {:?}", + non_qbits + ))); + } + + let bit_iter = match self.qubits.map_bits(qubits.iter()) { + Ok(bit_iter) => bit_iter, + Err(_) => { + return Err(DAGCircuitError::new_err(format!( + "qubits not in circuit: {:?}", + qubits + ))) + } + }; + let qubits: HashSet = bit_iter.collect(); + + let mut busy_bits = Vec::new(); + for bit in qubits.iter() { + if !self.is_wire_idle(py, &Wire::Qubit(*bit))? { + busy_bits.push(self.qubits.get(*bit).unwrap()); + } + } + + if !busy_bits.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "qubits not idle: {:?}", + busy_bits + ))); + } + + // Remove any references to bits. + let mut qregs_to_remove = Vec::new(); + for qreg in self.qregs.bind(py).values() { + for bit in qreg.iter()? { + let bit = bit?; + if qubits.contains(&self.qubits.find(&bit).unwrap()) { + qregs_to_remove.push(qreg); + break; + } + } + } + self.remove_qregs(py, &PyTuple::new_bound(py, qregs_to_remove))?; + + // Remove DAG in/out nodes etc. + for bit in qubits.iter() { + self.remove_idle_wire(py, Wire::Qubit(*bit))?; + } + + // Copy the current qubit mapping so we can use it while remapping + // wires used on edges and in operation qargs. + let old_qubits = self.qubits.clone(); + + // Remove the qubit indices, which will invalidate our mapping of Qubit to + // Python bits throughout the entire DAG. + self.qubits.remove_indices(py, qubits.clone())?; + + // Update input/output maps to use new Qubits. + let io_mapping: HashMap = self + .qubit_io_map + .drain(..) + .enumerate() + .filter_map(|(k, v)| { + let qubit = Qubit(k as u32); + if qubits.contains(&qubit) { + None + } else { + Some(( + self.qubits + .find(old_qubits.get(qubit).unwrap().bind(py)) + .unwrap(), + v, + )) + } + }) + .collect(); + + self.qubit_io_map = (0..io_mapping.len()) + .map(|idx| { + let qubit = Qubit(idx as u32); + io_mapping[&qubit] + }) + .collect(); + + // Update edges to use the new Qubits. + for edge_weight in self.dag.edge_weights_mut() { + if let Wire::Qubit(b) = edge_weight { + *b = self + .qubits + .find(old_qubits.get(*b).unwrap().bind(py)) + .unwrap(); + } + } + + // Update operation qargs to use the new Qubits. + for node_weight in self.dag.node_weights_mut() { + match node_weight { + NodeType::Operation(op) => { + let qargs = self.qargs_cache.intern(op.qubits); + let qarg_bits = old_qubits + .map_indices(&qargs[..]) + .map(|b| b.bind(py).clone()); + let mapped_qargs = self.qubits.map_bits(qarg_bits)?.collect(); + let qubits = Interner::intern(&mut self.qargs_cache, mapped_qargs)?; + op.qubits = qubits; + } + NodeType::QubitIn(q) | NodeType::QubitOut(q) => { + *q = self + .qubits + .find(old_qubits.get(*q).unwrap().bind(py)) + .unwrap(); + } + _ => (), + } + } + + // Update bit locations. + let bit_locations = self.qubit_locations.bind(py); + for (i, bit) in self.qubits.bits().iter().enumerate() { + let raw_loc = bit_locations.get_item(bit)?.unwrap(); + let loc = raw_loc.downcast::().unwrap(); + loc.borrow_mut().index = i; + bit_locations.set_item(bit, loc)?; + } + Ok(()) + } + + /// Remove quantum registers from the circuit, leaving underlying bits + /// in place. + /// + /// Raises: + /// DAGCircuitError: a qreg is not a QuantumRegister, or is not in + /// the circuit. + #[pyo3(signature = (*qregs))] + fn remove_qregs(&mut self, py: Python, qregs: &Bound) -> PyResult<()> { + let mut non_regs = Vec::new(); + let mut unknown_regs = Vec::new(); + let self_bound_qregs = self.qregs.bind(py); + for reg in qregs.iter() { + if !reg.is_instance(imports::QUANTUM_REGISTER.get_bound(py))? { + non_regs.push(reg); + } else if let Some(existing_qreg) = + self_bound_qregs.get_item(®.getattr(intern!(py, "name"))?)? + { + if !existing_qreg.eq(®)? { + unknown_regs.push(reg); + } + } else { + unknown_regs.push(reg); + } + } + if !non_regs.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "qregs not of type QuantumRegister: {:?}", + non_regs + ))); + } + if !unknown_regs.is_empty() { + return Err(DAGCircuitError::new_err(format!( + "qregs not in circuit: {:?}", + unknown_regs + ))); + } + + for qreg in qregs { + self.qregs + .bind(py) + .del_item(qreg.getattr(intern!(py, "name"))?)?; + for (i, bit) in qreg.iter()?.enumerate() { + let bit = bit?; + let bit_position = self + .qubit_locations + .bind(py) + .get_item(bit)? + .unwrap() + .downcast_into_exact::()?; + bit_position + .borrow() + .registers + .bind(py) + .as_any() + .call_method1(intern!(py, "remove"), ((&qreg, i),))?; + } + } + Ok(()) + } + + /// Verify that the condition is valid. + /// + /// Args: + /// name (string): used for error reporting + /// condition (tuple or None): a condition tuple (ClassicalRegister, int) or (Clbit, bool) + /// + /// Raises: + /// DAGCircuitError: if conditioning on an invalid register + fn _check_condition(&self, py: Python, name: &str, condition: &Bound) -> PyResult<()> { + if condition.is_none() { + return Ok(()); + } + + let resources = self.control_flow_module.condition_resources(condition)?; + for reg in resources.cregs.bind(py) { + if !self + .cregs + .bind(py) + .contains(reg.getattr(intern!(py, "name"))?)? + { + return Err(DAGCircuitError::new_err(format!( + "invalid creg in condition for {}", + name + ))); + } + } + + for bit in resources.clbits.bind(py) { + if self.clbits.find(&bit).is_none() { + return Err(DAGCircuitError::new_err(format!( + "invalid clbits in condition for {}", + name + ))); + } + } + + Ok(()) + } + + /// Return a copy of self with the same structure but empty. + /// + /// That structure includes: + /// * name and other metadata + /// * global phase + /// * duration + /// * all the qubits and clbits, including the registers. + /// + /// Returns: + /// DAGCircuit: An empty copy of self. + #[pyo3(signature = (*, vars_mode="alike"))] + fn copy_empty_like(&self, py: Python, vars_mode: &str) -> PyResult { + let mut target_dag = DAGCircuit::new(py)?; + target_dag.name = self.name.as_ref().map(|n| n.clone_ref(py)); + target_dag.global_phase = self.global_phase.clone(); + target_dag.duration = self.duration.as_ref().map(|d| d.clone_ref(py)); + target_dag.unit.clone_from(&self.unit); + target_dag.metadata = self.metadata.as_ref().map(|m| m.clone_ref(py)); + target_dag.qargs_cache = self.qargs_cache.clone(); + target_dag.cargs_cache = self.cargs_cache.clone(); + + for bit in self.qubits.bits() { + target_dag.add_qubit_unchecked(py, bit.bind(py))?; + } + for bit in self.clbits.bits() { + target_dag.add_clbit_unchecked(py, bit.bind(py))?; + } + for reg in self.qregs.bind(py).values() { + target_dag.add_qreg(py, ®)?; + } + for reg in self.cregs.bind(py).values() { + target_dag.add_creg(py, ®)?; + } + if vars_mode == "alike" { + for var in self.vars_by_type[DAGVarType::Input as usize] + .bind(py) + .iter() + { + target_dag.add_var(py, &var, DAGVarType::Input)?; + } + for var in self.vars_by_type[DAGVarType::Capture as usize] + .bind(py) + .iter() + { + target_dag.add_var(py, &var, DAGVarType::Capture)?; + } + for var in self.vars_by_type[DAGVarType::Declare as usize] + .bind(py) + .iter() + { + target_dag.add_var(py, &var, DAGVarType::Declare)?; + } + } else if vars_mode == "captures" { + for var in self.vars_by_type[DAGVarType::Input as usize] + .bind(py) + .iter() + { + target_dag.add_var(py, &var, DAGVarType::Capture)?; + } + for var in self.vars_by_type[DAGVarType::Capture as usize] + .bind(py) + .iter() + { + target_dag.add_var(py, &var, DAGVarType::Capture)?; + } + for var in self.vars_by_type[DAGVarType::Declare as usize] + .bind(py) + .iter() + { + target_dag.add_var(py, &var, DAGVarType::Capture)?; + } + } else if vars_mode != "drop" { + return Err(PyValueError::new_err(format!( + "unknown vars_mode: '{}'", + vars_mode + ))); + } + + Ok(target_dag) + } + + #[pyo3(signature=(node, check=false))] + fn _apply_op_node_back( + &mut self, + py: Python, + node: &Bound, + check: bool, + ) -> PyResult<()> { + if let NodeType::Operation(inst) = self.pack_into(py, node)? { + if check { + self.check_op_addition(py, &inst)?; + } + + self.push_back(py, inst)?; + Ok(()) + } else { + Err(PyTypeError::new_err("Invalid node type input")) + } + } + + /// Apply an operation to the output of the circuit. + /// + /// Args: + /// op (qiskit.circuit.Operation): the operation associated with the DAG node + /// qargs (tuple[~qiskit.circuit.Qubit]): qubits that op will be applied to + /// cargs (tuple[Clbit]): cbits that op will be applied to + /// check (bool): If ``True`` (default), this function will enforce that the + /// :class:`.DAGCircuit` data-structure invariants are maintained (all ``qargs`` are + /// :class:`~.circuit.Qubit`\\ s, all are in the DAG, etc). If ``False``, the caller *must* + /// uphold these invariants itself, but the cost of several checks will be skipped. + /// This is most useful when building a new DAG from a source of known-good nodes. + /// Returns: + /// DAGOpNode: the node for the op that was added to the dag + /// + /// Raises: + /// DAGCircuitError: if a leaf node is connected to multiple outputs + #[pyo3(name = "apply_operation_back", signature = (op, qargs=None, cargs=None, *, check=true))] + fn py_apply_operation_back( + &mut self, + py: Python, + op: Bound, + qargs: Option, + cargs: Option, + check: bool, + ) -> PyResult> { + let py_op = op.extract::()?; + let qargs = qargs.map(|q| q.value); + let cargs = cargs.map(|c| c.value); + let node = { + let qubits_id = Interner::intern( + &mut self.qargs_cache, + self.qubits.map_bits(qargs.iter().flatten())?.collect(), + )?; + let clbits_id = Interner::intern( + &mut self.cargs_cache, + self.clbits.map_bits(cargs.iter().flatten())?.collect(), + )?; + let instr = PackedInstruction { + op: py_op.operation, + qubits: qubits_id, + clbits: clbits_id, + params: (!py_op.params.is_empty()).then(|| Box::new(py_op.params)), + extra_attrs: py_op.extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op: op.unbind().into(), + }; + + if check { + self.check_op_addition(py, &instr)?; + } + self.push_back(py, instr)? + }; + + self.get_node(py, node) + } + + /// Apply an operation to the input of the circuit. + /// + /// Args: + /// op (qiskit.circuit.Operation): the operation associated with the DAG node + /// qargs (tuple[~qiskit.circuit.Qubit]): qubits that op will be applied to + /// cargs (tuple[Clbit]): cbits that op will be applied to + /// check (bool): If ``True`` (default), this function will enforce that the + /// :class:`.DAGCircuit` data-structure invariants are maintained (all ``qargs`` are + /// :class:`~.circuit.Qubit`\\ s, all are in the DAG, etc). If ``False``, the caller *must* + /// uphold these invariants itself, but the cost of several checks will be skipped. + /// This is most useful when building a new DAG from a source of known-good nodes. + /// Returns: + /// DAGOpNode: the node for the op that was added to the dag + /// + /// Raises: + /// DAGCircuitError: if initial nodes connected to multiple out edges + #[pyo3(name = "apply_operation_front", signature = (op, qargs=None, cargs=None, *, check=true))] + fn py_apply_operation_front( + &mut self, + py: Python, + op: Bound, + qargs: Option, + cargs: Option, + check: bool, + ) -> PyResult> { + let py_op = op.extract::()?; + let qargs = qargs.map(|q| q.value); + let cargs = cargs.map(|c| c.value); + let node = { + let qubits_id = Interner::intern( + &mut self.qargs_cache, + self.qubits.map_bits(qargs.iter().flatten())?.collect(), + )?; + let clbits_id = Interner::intern( + &mut self.cargs_cache, + self.clbits.map_bits(cargs.iter().flatten())?.collect(), + )?; + let instr = PackedInstruction { + op: py_op.operation, + qubits: qubits_id, + clbits: clbits_id, + params: (!py_op.params.is_empty()).then(|| Box::new(py_op.params)), + extra_attrs: py_op.extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op: op.unbind().into(), + }; + + if check { + self.check_op_addition(py, &instr)?; + } + self.push_front(py, instr)? + }; + + self.get_node(py, node) + } + + /// Compose the ``other`` circuit onto the output of this circuit. + /// + /// A subset of input wires of ``other`` are mapped + /// to a subset of output wires of this circuit. + /// + /// ``other`` can be narrower or of equal width to ``self``. + /// + /// Args: + /// other (DAGCircuit): circuit to compose with self + /// qubits (list[~qiskit.circuit.Qubit|int]): qubits of self to compose onto. + /// clbits (list[Clbit|int]): clbits of self to compose onto. + /// front (bool): If True, front composition will be performed (not implemented yet) + /// inplace (bool): If True, modify the object. Otherwise return composed circuit. + /// inline_captures (bool): If ``True``, variables marked as "captures" in the ``other`` DAG + /// will be inlined onto existing uses of those same variables in ``self``. If ``False``, + /// all variables in ``other`` are required to be distinct from ``self``, and they will + /// be added to ``self``. + /// + /// .. + /// Note: unlike `QuantumCircuit.compose`, there's no `var_remap` argument here. That's + /// because the `DAGCircuit` inner-block structure isn't set up well to allow the recursion, + /// and `DAGCircuit.compose` is generally only used to rebuild a DAG from layers within + /// itself than to join unrelated circuits. While there's no strong motivating use-case + /// (unlike the `QuantumCircuit` equivalent), it's safer and more performant to not provide + /// the option. + /// + /// Returns: + /// DAGCircuit: the composed dag (returns None if inplace==True). + /// + /// Raises: + /// DAGCircuitError: if ``other`` is wider or there are duplicate edge mappings. + #[allow(clippy::too_many_arguments)] + #[pyo3(signature = (other, qubits=None, clbits=None, front=false, inplace=true, *, inline_captures=false))] + fn compose( + slf: PyRefMut, + py: Python, + other: &DAGCircuit, + qubits: Option>, + clbits: Option>, + front: bool, + inplace: bool, + inline_captures: bool, + ) -> PyResult> { + if front { + return Err(DAGCircuitError::new_err( + "Front composition not supported yet.", + )); + } + + if other.qubits.len() > slf.qubits.len() || other.clbits.len() > slf.clbits.len() { + return Err(DAGCircuitError::new_err( + "Trying to compose with another DAGCircuit which has more 'in' edges.", + )); + } + + // Number of qubits and clbits must match number in circuit or None + let identity_qubit_map = other + .qubits + .bits() + .iter() + .zip(slf.qubits.bits()) + .into_py_dict_bound(py); + let identity_clbit_map = other + .clbits + .bits() + .iter() + .zip(slf.clbits.bits()) + .into_py_dict_bound(py); + + let qubit_map: Bound = match qubits { + None => identity_qubit_map.clone(), + Some(qubits) => { + if qubits.len() != other.qubits.len() { + return Err(DAGCircuitError::new_err(concat!( + "Number of items in qubits parameter does not", + " match number of qubits in the circuit." + ))); + } + + let self_qubits = slf.qubits.cached().bind(py); + let other_qubits = other.qubits.cached().bind(py); + let dict = PyDict::new_bound(py); + for (i, q) in qubits.iter().enumerate() { + let q = if q.is_instance_of::() { + self_qubits.get_item(q.extract()?)? + } else { + q + }; + + dict.set_item(other_qubits.get_item(i)?, q)?; + } + dict + } + }; + + let clbit_map: Bound = match clbits { + None => identity_clbit_map.clone(), + Some(clbits) => { + if clbits.len() != other.clbits.len() { + return Err(DAGCircuitError::new_err(concat!( + "Number of items in clbits parameter does not", + " match number of clbits in the circuit." + ))); + } + + let self_clbits = slf.clbits.cached().bind(py); + let other_clbits = other.clbits.cached().bind(py); + let dict = PyDict::new_bound(py); + for (i, q) in clbits.iter().enumerate() { + let q = if q.is_instance_of::() { + self_clbits.get_item(q.extract()?)? + } else { + q + }; + + dict.set_item(other_clbits.get_item(i)?, q)?; + } + dict + } + }; + + let edge_map = if qubit_map.is_empty() && clbit_map.is_empty() { + // try to do a 1-1 mapping in order + identity_qubit_map + .iter() + .chain(identity_clbit_map.iter()) + .into_py_dict_bound(py) + } else { + qubit_map + .iter() + .chain(clbit_map.iter()) + .into_py_dict_bound(py) + }; + + // Chck duplicates in wire map. + { + let edge_map_values: Vec<_> = edge_map.values().iter().collect(); + if PySet::new_bound(py, edge_map_values.as_slice())?.len() != edge_map.len() { + return Err(DAGCircuitError::new_err("duplicates in wire_map")); + } + } + + // Compose + let mut dag: PyRefMut = if inplace { + slf + } else { + Py::new(py, slf.clone())?.into_bound(py).borrow_mut() + }; + + dag.global_phase = add_global_phase(py, &dag.global_phase, &other.global_phase)?; + + for (gate, cals) in other.calibrations.iter() { + let calibrations = match dag.calibrations.get(gate) { + Some(calibrations) => calibrations, + None => { + dag.calibrations + .insert(gate.clone(), PyDict::new_bound(py).unbind()); + &dag.calibrations[gate] + } + }; + calibrations.bind(py).update(cals.bind(py).as_mapping())?; + } + + // This is all the handling we need for realtime variables, if there's no remapping. They: + // + // * get added to the DAG and then operations involving them get appended on normally. + // * get inlined onto an existing variable, then operations get appended normally. + // * there's a clash or a failed inlining, and we just raise an error. + // + // Notably if there's no remapping, there's no need to recurse into control-flow or to do any + // Var rewriting during the Expr visits. + for var in other.iter_input_vars(py)?.bind(py) { + dag.add_input_var(py, &var?)?; + } + if inline_captures { + for var in other.iter_captured_vars(py)?.bind(py) { + let var = var?; + if !dag.has_var(&var)? { + return Err(DAGCircuitError::new_err(format!("Variable '{}' to be inlined is not in the base DAG. If you wanted it to be automatically added, use `inline_captures=False`.", var))); + } + } + } else { + for var in other.iter_captured_vars(py)?.bind(py) { + dag.add_captured_var(py, &var?)?; + } + } + for var in other.iter_declared_vars(py)?.bind(py) { + dag.add_declared_var(py, &var?)?; + } + + let variable_mapper = PyVariableMapper::new( + py, + dag.cregs.bind(py).values().into_any(), + Some(edge_map.clone()), + None, + Some(wrap_pyfunction_bound!(reject_new_register, py)?.to_object(py)), + )?; + + for node in other.topological_nodes()? { + match &other.dag[node] { + NodeType::QubitIn(q) => { + let bit = other.qubits.get(*q).unwrap().bind(py); + let m_wire = edge_map.get_item(bit)?.unwrap_or_else(|| bit.clone()); + let wire_in_dag = dag.qubits.find(&m_wire); + + if wire_in_dag.is_none() + || (dag.qubit_io_map.len() - 1 < wire_in_dag.unwrap().0 as usize) + { + return Err(DAGCircuitError::new_err(format!( + "wire {} not in self", + m_wire, + ))); + } + // TODO: Python code has check here if node.wire is in other._wires. Why? + } + NodeType::ClbitIn(c) => { + let bit = other.clbits.get(*c).unwrap().bind(py); + let m_wire = edge_map.get_item(bit)?.unwrap_or_else(|| bit.clone()); + let wire_in_dag = dag.clbits.find(&m_wire); + if wire_in_dag.is_none() + || dag.clbit_io_map.len() - 1 < wire_in_dag.unwrap().0 as usize + { + return Err(DAGCircuitError::new_err(format!( + "wire {} not in self", + m_wire, + ))); + } + // TODO: Python code has check here if node.wire is in other._wires. Why? + } + NodeType::Operation(op) => { + let m_qargs = { + let qubits = other + .qubits + .map_indices(other.qargs_cache.intern(op.qubits).as_slice()); + let mut mapped = Vec::with_capacity(qubits.len()); + for bit in qubits { + mapped.push( + edge_map + .get_item(bit)? + .unwrap_or_else(|| bit.bind(py).clone()), + ); + } + PyTuple::new_bound(py, mapped) + }; + let m_cargs = { + let clbits = other + .clbits + .map_indices(other.cargs_cache.intern(op.clbits).as_slice()); + let mut mapped = Vec::with_capacity(clbits.len()); + for bit in clbits { + mapped.push( + edge_map + .get_item(bit)? + .unwrap_or_else(|| bit.bind(py).clone()), + ); + } + PyTuple::new_bound(py, mapped) + }; + + // We explicitly create a mutable py_op here since we might + // update the condition. + let mut py_op = op.unpack_py_op(py)?.into_bound(py); + if py_op.getattr(intern!(py, "mutable"))?.extract::()? { + py_op = py_op.call_method0(intern!(py, "to_mutable"))?; + } + + if let Some(condition) = op.condition() { + // TODO: do we need to check for condition.is_none()? + let condition = variable_mapper.map_condition(condition.bind(py), true)?; + if !op.op.control_flow() { + py_op = py_op.call_method1( + intern!(py, "c_if"), + condition.downcast::()?, + )?; + } else { + py_op.setattr(intern!(py, "condition"), condition)?; + } + } else if py_op.is_instance(imports::SWITCH_CASE_OP.get_bound(py))? { + py_op.setattr( + intern!(py, "target"), + variable_mapper.map_target(&py_op.getattr(intern!(py, "target"))?)?, + )?; + }; + + dag.py_apply_operation_back( + py, + py_op, + Some(TupleLikeArg { value: m_qargs }), + Some(TupleLikeArg { value: m_cargs }), + false, + )?; + } + // If its a Var wire, we already checked that it exists in the destination. + NodeType::VarIn(_) + | NodeType::VarOut(_) + | NodeType::QubitOut(_) + | NodeType::ClbitOut(_) => (), + } + } + + if !inplace { + Ok(Some(dag.into_py(py))) + } else { + Ok(None) + } + } + + /// Reverse the operations in the ``self`` circuit. + /// + /// Returns: + /// DAGCircuit: the reversed dag. + fn reverse_ops<'py>(slf: PyRef, py: Python<'py>) -> PyResult> { + let qc = imports::DAG_TO_CIRCUIT.get_bound(py).call1((slf,))?; + let reversed = qc.call_method0("reverse_ops")?; + imports::CIRCUIT_TO_DAG.get_bound(py).call1((reversed,)) + } + + /// Return idle wires. + /// + /// Args: + /// ignore (list(str)): List of node names to ignore. Default: [] + /// + /// Yields: + /// Bit: Bit in idle wire. + /// + /// Raises: + /// DAGCircuitError: If the DAG is invalid + fn idle_wires(&self, py: Python, ignore: Option<&Bound>) -> PyResult> { + let mut result: Vec = Vec::new(); + let wires = (0..self.qubit_io_map.len()) + .map(|idx| Wire::Qubit(Qubit(idx as u32))) + .chain((0..self.clbit_io_map.len()).map(|idx| Wire::Clbit(Clbit(idx as u32)))) + .chain(self.var_input_map.keys(py).map(Wire::Var)); + match ignore { + Some(ignore) => { + // Convert the list to a Rust set. + let ignore_set = ignore + .into_iter() + .map(|s| s.extract()) + .collect::>>()?; + for wire in wires { + let nodes_found = self.nodes_on_wire(py, &wire, true).into_iter().any(|node| { + let weight = self.dag.node_weight(node).unwrap(); + if let NodeType::Operation(packed) = weight { + !ignore_set.contains(packed.op.name()) + } else { + false + } + }); + + if !nodes_found { + result.push(match wire { + Wire::Qubit(qubit) => self.qubits.get(qubit).unwrap().clone_ref(py), + Wire::Clbit(clbit) => self.clbits.get(clbit).unwrap().clone_ref(py), + Wire::Var(var) => var, + }); + } + } + } + None => { + for wire in wires { + if self.is_wire_idle(py, &wire)? { + result.push(match wire { + Wire::Qubit(qubit) => self.qubits.get(qubit).unwrap().clone_ref(py), + Wire::Clbit(clbit) => self.clbits.get(clbit).unwrap().clone_ref(py), + Wire::Var(var) => var, + }); + } + } + } + } + Ok(PyTuple::new_bound(py, result).into_any().iter()?.unbind()) + } + + /// Return the number of operations. If there is control flow present, this count may only + /// be an estimate, as the complete control-flow path cannot be statically known. + /// + /// Args: + /// recurse: if ``True``, then recurse into control-flow operations. For loops with + /// known-length iterators are counted unrolled. If-else blocks sum both of the two + /// branches. While loops are counted as if the loop body runs once only. Defaults to + /// ``False`` and raises :class:`.DAGCircuitError` if any control flow is present, to + /// avoid silently returning a mostly meaningless number. + /// + /// Returns: + /// int: the circuit size + /// + /// Raises: + /// DAGCircuitError: if an unknown :class:`.ControlFlowOp` is present in a call with + /// ``recurse=True``, or any control flow is present in a non-recursive call. + #[pyo3(signature= (*, recurse=false))] + fn size(&self, py: Python, recurse: bool) -> PyResult { + let mut length = self.dag.node_count() - (self.width() * 2); + if !recurse { + if CONTROL_FLOW_OP_NAMES + .iter() + .any(|n| self.op_names.contains_key(&n.to_string())) + { + return Err(DAGCircuitError::new_err(concat!( + "Size with control flow is ambiguous.", + " You may use `recurse=True` to get a result", + " but see this method's documentation for the meaning of this." + ))); + } + return Ok(length); + } + + let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); + for node_index in + self.op_nodes_by_py_type(imports::CONTROL_FLOW_OP.get_bound(py).downcast()?, true) + { + let NodeType::Operation(node) = &self.dag[node_index] else { + return Err(DAGCircuitError::new_err("unknown control-flow type")); + }; + let OperationRef::Instruction(inst) = node.op.view() else { + unreachable!("Control Flow operations must be a PyInstruction"); + }; + let inst_bound = inst.instruction.bind(py); + if inst_bound.is_instance(imports::FOR_LOOP_OP.get_bound(py))? { + let raw_blocks = inst_bound.getattr("blocks")?; + let blocks: &Bound = raw_blocks.downcast()?; + let block_zero = blocks.get_item(0).unwrap(); + let inner_dag: &DAGCircuit = + &circuit_to_dag.call1((block_zero.clone(),))?.extract()?; + length += node.params_view().len() * inner_dag.size(py, true)? + } else if inst_bound.is_instance(imports::WHILE_LOOP_OP.get_bound(py))? { + let raw_blocks = inst_bound.getattr("blocks")?; + let blocks: &Bound = raw_blocks.downcast()?; + let block_zero = blocks.get_item(0).unwrap(); + let inner_dag: &DAGCircuit = + &circuit_to_dag.call1((block_zero.clone(),))?.extract()?; + length += inner_dag.size(py, true)? + } else if inst_bound.is_instance(imports::IF_ELSE_OP.get_bound(py))? + || inst_bound.is_instance(imports::SWITCH_CASE_OP.get_bound(py))? + { + let raw_blocks = inst_bound.getattr("blocks")?; + let blocks: &Bound = raw_blocks.downcast()?; + for block in blocks.iter() { + let inner_dag: &DAGCircuit = + &circuit_to_dag.call1((block.clone(),))?.extract()?; + length += inner_dag.size(py, true)?; + } + } else { + continue; + } + // We don't count a control-flow node itself! + length -= 1; + } + Ok(length) + } + + /// Return the circuit depth. If there is control flow present, this count may only be an + /// estimate, as the complete control-flow path cannot be statically known. + /// + /// Args: + /// recurse: if ``True``, then recurse into control-flow operations. For loops + /// with known-length iterators are counted as if the loop had been manually unrolled + /// (*i.e.* with each iteration of the loop body written out explicitly). + /// If-else blocks take the longer case of the two branches. While loops are counted as + /// if the loop body runs once only. Defaults to ``False`` and raises + /// :class:`.DAGCircuitError` if any control flow is present, to avoid silently + /// returning a nonsensical number. + /// + /// Returns: + /// int: the circuit depth + /// + /// Raises: + /// DAGCircuitError: if not a directed acyclic graph + /// DAGCircuitError: if unknown control flow is present in a recursive call, or any control + /// flow is present in a non-recursive call. + #[pyo3(signature= (*, recurse=false))] + fn depth(&self, py: Python, recurse: bool) -> PyResult { + if self.qubits.is_empty() && self.clbits.is_empty() && self.vars_info.is_empty() { + return Ok(0); + } + + Ok(if recurse { + let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); + let mut node_lookup: HashMap = HashMap::new(); + + for node_index in + self.op_nodes_by_py_type(imports::CONTROL_FLOW_OP.get_bound(py).downcast()?, true) + { + if let NodeType::Operation(node) = &self.dag[node_index] { + if let OperationRef::Instruction(inst) = node.op.view() { + let inst_bound = inst.instruction.bind(py); + let weight = + if inst_bound.is_instance(imports::FOR_LOOP_OP.get_bound(py))? { + node.params_view().len() + } else { + 1 + }; + if weight == 0 { + node_lookup.insert(node_index, 0); + } else { + let raw_blocks = inst_bound.getattr("blocks")?; + let blocks = raw_blocks.downcast::()?; + let mut block_weights: Vec = Vec::with_capacity(blocks.len()); + for block in blocks.iter() { + let inner_dag: &DAGCircuit = + &circuit_to_dag.call1((block,))?.extract()?; + block_weights.push(inner_dag.depth(py, true)?); + } + node_lookup + .insert(node_index, weight * block_weights.iter().max().unwrap()); + } + } + } + } + + let weight_fn = |edge: EdgeReference<'_, Wire>| -> Result { + Ok(*node_lookup.get(&edge.target()).unwrap_or(&1)) + }; + match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { + Some(res) => res.1, + None => return Err(DAGCircuitError::new_err("not a DAG")), + } + } else { + if CONTROL_FLOW_OP_NAMES + .iter() + .any(|x| self.op_names.contains_key(&x.to_string())) + { + return Err(DAGCircuitError::new_err("Depth with control flow is ambiguous. You may use `recurse=True` to get a result, but see this method's documentation for the meaning of this.")); + } + + let weight_fn = |_| -> Result { Ok(1) }; + match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { + Some(res) => res.1, + None => return Err(DAGCircuitError::new_err("not a DAG")), + } + } - 1) + } + + /// Return the total number of qubits + clbits used by the circuit. + /// This function formerly returned the number of qubits by the calculation + /// return len(self._wires) - self.num_clbits() + /// but was changed by issue #2564 to return number of qubits + clbits + /// with the new function DAGCircuit.num_qubits replacing the former + /// semantic of DAGCircuit.width(). + fn width(&self) -> usize { + self.qubits.len() + self.clbits.len() + self.vars_info.len() + } + + /// Return the total number of qubits used by the circuit. + /// num_qubits() replaces former use of width(). + /// DAGCircuit.width() now returns qubits + clbits for + /// consistency with Circuit.width() [qiskit-terra #2564]. + pub fn num_qubits(&self) -> usize { + self.qubits.len() + } + + /// Return the total number of classical bits used by the circuit. + pub fn num_clbits(&self) -> usize { + self.clbits.len() + } + + /// Compute how many components the circuit can decompose into. + fn num_tensor_factors(&self) -> usize { + // This function was forked from rustworkx's + // number_weekly_connected_components() function as of 0.15.0: + // https://github.com/Qiskit/rustworkx/blob/0.15.0/src/connectivity/mod.rs#L215-L235 + + let mut weak_components = self.dag.node_count(); + let mut vertex_sets = UnionFind::new(self.dag.node_bound()); + for edge in self.dag.edge_references() { + let (a, b) = (edge.source(), edge.target()); + // union the two vertices of the edge + if vertex_sets.union(a.index(), b.index()) { + weak_components -= 1 + }; + } + weak_components + } + + fn __eq__(&self, py: Python, other: &DAGCircuit) -> PyResult { + // Try to convert to float, but in case of unbound ParameterExpressions + // a TypeError will be raise, fallback to normal equality in those + // cases. + let phase_is_close = |self_phase: f64, other_phase: f64| -> bool { + ((self_phase - other_phase + PI).rem_euclid(2. * PI) - PI).abs() <= 1.0e-10 + }; + let normalize_param = |param: &Param| { + if let Param::ParameterExpression(ob) = param { + ob.bind(py) + .call_method0(intern!(py, "numeric")) + .ok() + .map(|ob| ob.extract::()) + .unwrap_or_else(|| Ok(param.clone())) + } else { + Ok(param.clone()) + } + }; + + let phase_eq = match [ + normalize_param(&self.global_phase)?, + normalize_param(&other.global_phase)?, + ] { + [Param::Float(self_phase), Param::Float(other_phase)] => { + Ok(phase_is_close(self_phase, other_phase)) + } + _ => self.global_phase.eq(py, &other.global_phase), + }?; + if !phase_eq { + return Ok(false); + } + if self.calibrations.len() != other.calibrations.len() { + return Ok(false); + } + + for (k, v1) in &self.calibrations { + match other.calibrations.get(k) { + Some(v2) => { + if !v1.bind(py).eq(v2.bind(py))? { + return Ok(false); + } + } + None => { + return Ok(false); + } + } + } + + // We don't do any semantic equivalence between Var nodes, as things stand; DAGs can only be + // equal in our mind if they use the exact same UUID vars. + for (our_vars, their_vars) in self.vars_by_type.iter().zip(&other.vars_by_type) { + if !our_vars.bind(py).eq(their_vars)? { + return Ok(false); + } + } + + let self_bit_indices = { + let indices = self + .qubits + .bits() + .iter() + .chain(self.clbits.bits()) + .enumerate() + .map(|(idx, bit)| (bit, idx)); + indices.into_py_dict_bound(py) + }; + + let other_bit_indices = { + let indices = other + .qubits + .bits() + .iter() + .chain(other.clbits.bits()) + .enumerate() + .map(|(idx, bit)| (bit, idx)); + indices.into_py_dict_bound(py) + }; + + // Check if qregs are the same. + let self_qregs = self.qregs.bind(py); + let other_qregs = other.qregs.bind(py); + if self_qregs.len() != other_qregs.len() { + return Ok(false); + } + for (regname, self_bits) in self_qregs { + let self_bits = self_bits + .getattr("_bits")? + .downcast_into_exact::()?; + let other_bits = match other_qregs.get_item(regname)? { + Some(bits) => bits.getattr("_bits")?.downcast_into_exact::()?, + None => return Ok(false), + }; + if !self + .qubits + .map_bits(self_bits)? + .eq(other.qubits.map_bits(other_bits)?) + { + return Ok(false); + } + } + + // Check if cregs are the same. + let self_cregs = self.cregs.bind(py); + let other_cregs = other.cregs.bind(py); + if self_cregs.len() != other_cregs.len() { + return Ok(false); + } + + for (regname, self_bits) in self_cregs { + let self_bits = self_bits + .getattr("_bits")? + .downcast_into_exact::()?; + let other_bits = match other_cregs.get_item(regname)? { + Some(bits) => bits.getattr("_bits")?.downcast_into_exact::()?, + None => return Ok(false), + }; + if !self + .clbits + .map_bits(self_bits)? + .eq(other.clbits.map_bits(other_bits)?) + { + return Ok(false); + } + } + + // Check for VF2 isomorphic match. + let legacy_condition_eq = imports::LEGACY_CONDITION_CHECK.get_bound(py); + let condition_op_check = imports::CONDITION_OP_CHECK.get_bound(py); + let switch_case_op_check = imports::SWITCH_CASE_OP_CHECK.get_bound(py); + let for_loop_op_check = imports::FOR_LOOP_OP_CHECK.get_bound(py); + let node_match = |n1: &NodeType, n2: &NodeType| -> PyResult { + match [n1, n2] { + [NodeType::Operation(inst1), NodeType::Operation(inst2)] => { + if inst1.op.name() != inst2.op.name() { + return Ok(false); + } + let check_args = || -> bool { + let node1_qargs = self.qargs_cache.intern(inst1.qubits); + let node2_qargs = other.qargs_cache.intern(inst2.qubits); + let node1_cargs = self.cargs_cache.intern(inst1.clbits); + let node2_cargs = other.cargs_cache.intern(inst2.clbits); + if SEMANTIC_EQ_SYMMETRIC.contains(&inst1.op.name()) { + let node1_qargs = + node1_qargs.iter().copied().collect::>(); + let node2_qargs = + node2_qargs.iter().copied().collect::>(); + let node1_cargs = + node1_cargs.iter().copied().collect::>(); + let node2_cargs = + node2_cargs.iter().copied().collect::>(); + if node1_qargs != node2_qargs || node1_cargs != node2_cargs { + return false; + } + } else if node1_qargs != node2_qargs || node1_cargs != node2_cargs { + return false; + } + true + }; + let check_conditions = || -> PyResult { + if let Some(cond1) = inst1 + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()) + { + if let Some(cond2) = inst2 + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()) + { + legacy_condition_eq + .call1((cond1, cond2, &self_bit_indices, &other_bit_indices))? + .extract::() + } else { + Ok(false) + } + } else { + Ok(inst2 + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()) + .is_none()) + } + }; + + match [inst1.op.view(), inst2.op.view()] { + [OperationRef::Standard(_op1), OperationRef::Standard(_op2)] => { + Ok(inst1.py_op_eq(py, inst2)? + && check_args() + && check_conditions()? + && inst1 + .params_view() + .iter() + .zip(inst2.params_view().iter()) + .all(|(a, b)| a.is_close(py, b, 1e-10).unwrap())) + } + [OperationRef::Instruction(op1), OperationRef::Instruction(op2)] => { + if op1.control_flow() && op2.control_flow() { + let n1 = self.unpack_into(py, NodeIndex::new(0), n1)?; + let n2 = other.unpack_into(py, NodeIndex::new(0), n2)?; + let name = op1.name(); + if name == "if_else" || name == "while_loop" { + condition_op_check + .call1((n1, n2, &self_bit_indices, &other_bit_indices))? + .extract() + } else if name == "switch_case" { + switch_case_op_check + .call1((n1, n2, &self_bit_indices, &other_bit_indices))? + .extract() + } else if name == "for_loop" { + for_loop_op_check + .call1((n1, n2, &self_bit_indices, &other_bit_indices))? + .extract() + } else { + Err(PyRuntimeError::new_err(format!( + "unhandled control-flow operation: {}", + name + ))) + } + } else { + Ok(inst1.py_op_eq(py, inst2)? + && check_args() + && check_conditions()?) + } + } + [OperationRef::Gate(_op1), OperationRef::Gate(_op2)] => { + Ok(inst1.py_op_eq(py, inst2)? && check_args() && check_conditions()?) + } + [OperationRef::Operation(_op1), OperationRef::Operation(_op2)] => { + Ok(inst1.py_op_eq(py, inst2)? && check_args()) + } + // Handle the case we end up with a pygate for a standardgate + // this typically only happens if it's a ControlledGate in python + // and we have mutable state set. + [OperationRef::Standard(_op1), OperationRef::Gate(_op2)] => { + Ok(inst1.py_op_eq(py, inst2)? && check_args() && check_conditions()?) + } + [OperationRef::Gate(_op1), OperationRef::Standard(_op2)] => { + Ok(inst1.py_op_eq(py, inst2)? && check_args() && check_conditions()?) + } + _ => Ok(false), + } + } + [NodeType::QubitIn(bit1), NodeType::QubitIn(bit2)] => Ok(bit1 == bit2), + [NodeType::ClbitIn(bit1), NodeType::ClbitIn(bit2)] => Ok(bit1 == bit2), + [NodeType::QubitOut(bit1), NodeType::QubitOut(bit2)] => Ok(bit1 == bit2), + [NodeType::ClbitOut(bit1), NodeType::ClbitOut(bit2)] => Ok(bit1 == bit2), + [NodeType::VarIn(var1), NodeType::VarIn(var2)] => var1.bind(py).eq(var2), + [NodeType::VarOut(var1), NodeType::VarOut(var2)] => var1.bind(py).eq(var2), + _ => Ok(false), + } + }; + + isomorphism::vf2::is_isomorphic( + &self.dag, + &other.dag, + node_match, + isomorphism::vf2::NoSemanticMatch, + true, + Ordering::Equal, + true, + None, + ) + .map_err(|e| match e { + isomorphism::vf2::IsIsomorphicError::NodeMatcherErr(e) => e, + _ => { + unreachable!() + } + }) + } + + /// Yield nodes in topological order. + /// + /// Args: + /// key (Callable): A callable which will take a DAGNode object and + /// return a string sort key. If not specified the + /// :attr:`~qiskit.dagcircuit.DAGNode.sort_key` attribute will be + /// used as the sort key for each node. + /// + /// Returns: + /// generator(DAGOpNode, DAGInNode, or DAGOutNode): node in topological order + #[pyo3(name = "topological_nodes")] + fn py_topological_nodes( + &self, + py: Python, + key: Option>, + ) -> PyResult> { + let nodes: PyResult> = if let Some(key) = key { + self.topological_key_sort(py, &key)? + .map(|node| self.get_node(py, node)) + .collect() + } else { + // Good path, using interner IDs. + self.topological_nodes()? + .map(|n| self.get_node(py, n)) + .collect() + }; + + Ok(PyTuple::new_bound(py, nodes?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Yield op nodes in topological order. + /// + /// Allowed to pass in specific key to break ties in top order + /// + /// Args: + /// key (Callable): A callable which will take a DAGNode object and + /// return a string sort key. If not specified the + /// :attr:`~qiskit.dagcircuit.DAGNode.sort_key` attribute will be + /// used as the sort key for each node. + /// + /// Returns: + /// generator(DAGOpNode): op node in topological order + #[pyo3(name = "topological_op_nodes")] + fn py_topological_op_nodes( + &self, + py: Python, + key: Option>, + ) -> PyResult> { + let nodes: PyResult> = if let Some(key) = key { + self.topological_key_sort(py, &key)? + .filter_map(|node| match self.dag.node_weight(node) { + Some(NodeType::Operation(_)) => Some(self.get_node(py, node)), + _ => None, + }) + .collect() + } else { + // Good path, using interner IDs. + self.topological_op_nodes()? + .map(|n| self.get_node(py, n)) + .collect() + }; + + Ok(PyTuple::new_bound(py, nodes?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Replace a block of nodes with a single node. + /// + /// This is used to consolidate a block of DAGOpNodes into a single + /// operation. A typical example is a block of gates being consolidated + /// into a single ``UnitaryGate`` representing the unitary matrix of the + /// block. + /// + /// Args: + /// node_block (List[DAGNode]): A list of dag nodes that represents the + /// node block to be replaced + /// op (qiskit.circuit.Operation): The operation to replace the + /// block with + /// wire_pos_map (Dict[Bit, int]): The dictionary mapping the bits to their positions in the + /// output ``qargs`` or ``cargs``. This is necessary to reconstruct the arg order over + /// multiple gates in the combined single op node. If a :class:`.Bit` is not in the + /// dictionary, it will not be added to the args; this can be useful when dealing with + /// control-flow operations that have inherent bits in their ``condition`` or ``target`` + /// fields. + /// cycle_check (bool): When set to True this method will check that + /// replacing the provided ``node_block`` with a single node + /// would introduce a cycle (which would invalidate the + /// ``DAGCircuit``) and will raise a ``DAGCircuitError`` if a cycle + /// would be introduced. This checking comes with a run time + /// penalty. If you can guarantee that your input ``node_block`` is + /// a contiguous block and won't introduce a cycle when it's + /// contracted to a single node, this can be set to ``False`` to + /// improve the runtime performance of this method. + /// + /// Raises: + /// DAGCircuitError: if ``cycle_check`` is set to ``True`` and replacing + /// the specified block introduces a cycle or if ``node_block`` is + /// empty. + /// + /// Returns: + /// DAGOpNode: The op node that replaces the block. + #[pyo3(signature = (node_block, op, wire_pos_map, cycle_check=true))] + fn replace_block_with_op( + &mut self, + py: Python, + node_block: Vec>, + op: Bound, + wire_pos_map: &Bound, + cycle_check: bool, + ) -> PyResult> { + // If node block is empty return early + if node_block.is_empty() { + return Err(DAGCircuitError::new_err( + "Can't replace an empty 'node_block'", + )); + } + + let mut qubit_pos_map: HashMap = HashMap::new(); + let mut clbit_pos_map: HashMap = HashMap::new(); + for (bit, index) in wire_pos_map.iter() { + if bit.is_instance(imports::QUBIT.get_bound(py))? { + qubit_pos_map.insert(self.qubits.find(&bit).unwrap(), index.extract()?); + } else if bit.is_instance(imports::CLBIT.get_bound(py))? { + clbit_pos_map.insert(self.clbits.find(&bit).unwrap(), index.extract()?); + } else { + return Err(DAGCircuitError::new_err( + "Wire map keys must be Qubit or Clbit instances.", + )); + } + } + + let block_ids: Vec<_> = node_block.iter().map(|n| n.node.unwrap()).collect(); + + let mut block_op_names = Vec::new(); + let mut block_qargs: HashSet = HashSet::new(); + let mut block_cargs: HashSet = HashSet::new(); + for nd in &block_ids { + let weight = self.dag.node_weight(*nd); + match weight { + Some(NodeType::Operation(packed)) => { + block_op_names.push(packed.op.name().to_string()); + block_qargs.extend(self.qargs_cache.intern(packed.qubits)); + block_cargs.extend(self.cargs_cache.intern(packed.clbits)); + + if let Some(condition) = packed.condition() { + block_cargs.extend( + self.clbits.map_bits( + self.control_flow_module + .condition_resources(condition.bind(py))? + .clbits + .bind(py), + )?, + ); + continue; + } + + // Add classical bits from SwitchCaseOp, if applicable. + if let OperationRef::Instruction(op) = packed.op.view() { + if op.name() == "switch_case" { + let op_bound = op.instruction.bind(py); + let target = op_bound.getattr(intern!(py, "target"))?; + if target.is_instance(imports::CLBIT.get_bound(py))? { + block_cargs.insert(self.clbits.find(&target).unwrap()); + } else if target + .is_instance(imports::CLASSICAL_REGISTER.get_bound(py))? + { + block_cargs.extend( + self.clbits + .map_bits(target.extract::>>()?)?, + ); + } else { + block_cargs.extend( + self.clbits.map_bits( + self.control_flow_module + .node_resources(&target)? + .clbits + .bind(py), + )?, + ); + } + } + } + } + Some(_) => { + return Err(DAGCircuitError::new_err( + "Nodes in 'node_block' must be of type 'DAGOpNode'.", + )) + } + None => { + return Err(DAGCircuitError::new_err( + "Node in 'node_block' not found in DAG.", + )) + } + } + } + + let mut block_qargs: Vec = block_qargs + .into_iter() + .filter(|q| qubit_pos_map.contains_key(q)) + .collect(); + block_qargs.sort_by_key(|q| qubit_pos_map[q]); + + let mut block_cargs: Vec = block_cargs + .into_iter() + .filter(|c| clbit_pos_map.contains_key(c)) + .collect(); + block_cargs.sort_by_key(|c| clbit_pos_map[c]); + + let py_op = op.extract::()?; + + if py_op.operation.num_qubits() as usize != block_qargs.len() { + return Err(DAGCircuitError::new_err(format!( + "Number of qubits in the replacement operation ({}) is not equal to the number of qubits in the block ({})!", py_op.operation.num_qubits(), block_qargs.len() + ))); + } + + let op_name = py_op.operation.name().to_string(); + let qubits = Interner::intern(&mut self.qargs_cache, block_qargs)?; + let clbits = Interner::intern(&mut self.cargs_cache, block_cargs)?; + let weight = NodeType::Operation(PackedInstruction { + op: py_op.operation, + qubits, + clbits, + params: (!py_op.params.is_empty()).then(|| Box::new(py_op.params)), + extra_attrs: py_op.extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op: op.unbind().into(), + }); + + let new_node = self + .dag + .contract_nodes(block_ids, weight, cycle_check) + .map_err(|e| match e { + ContractError::DAGWouldCycle => DAGCircuitError::new_err( + "Replacing the specified node block would introduce a cycle", + ), + })?; + + self.increment_op(op_name.as_str()); + for name in block_op_names { + self.decrement_op(name.as_str()); + } + + self.get_node(py, new_node) + } + + /// Replace one node with dag. + /// + /// Args: + /// node (DAGOpNode): node to substitute + /// input_dag (DAGCircuit): circuit that will substitute the node + /// wires (list[Bit] | Dict[Bit, Bit]): gives an order for (qu)bits + /// in the input circuit. If a list, then the bits refer to those in the ``input_dag``, + /// and the order gets matched to the node wires by qargs first, then cargs, then + /// conditions. If a dictionary, then a mapping of bits in the ``input_dag`` to those + /// that the ``node`` acts on. + /// propagate_condition (bool): If ``True`` (default), then any ``condition`` attribute on + /// the operation within ``node`` is propagated to each node in the ``input_dag``. If + /// ``False``, then the ``input_dag`` is assumed to faithfully implement suitable + /// conditional logic already. This is ignored for :class:`.ControlFlowOp`\\ s (i.e. + /// treated as if it is ``False``); replacements of those must already fulfill the same + /// conditional logic or this function would be close to useless for them. + /// + /// Returns: + /// dict: maps node IDs from `input_dag` to their new node incarnations in `self`. + /// + /// Raises: + /// DAGCircuitError: if met with unexpected predecessor/successors + #[pyo3(signature = (node, input_dag, wires=None, propagate_condition=true))] + fn substitute_node_with_dag( + &mut self, + py: Python, + node: &Bound, + input_dag: &DAGCircuit, + wires: Option>, + propagate_condition: bool, + ) -> PyResult> { + let (node_index, bound_node) = match node.downcast::() { + Ok(bound_node) => (bound_node.borrow().as_ref().node.unwrap(), bound_node), + Err(_) => return Err(DAGCircuitError::new_err("expected node DAGOpNode")), + }; + + let node = match &self.dag[node_index] { + NodeType::Operation(op) => op.clone(), + _ => return Err(DAGCircuitError::new_err("expected node")), + }; + + type WireMapsTuple = (HashMap, HashMap, Py); + + let build_wire_map = |wires: &Bound| -> PyResult { + let qargs_list = imports::BUILTIN_LIST + .get_bound(py) + .call1((bound_node.borrow().get_qargs(py),))?; + let qargs_list = qargs_list.downcast::().unwrap(); + let cargs_list = imports::BUILTIN_LIST + .get_bound(py) + .call1((bound_node.borrow().get_cargs(py),))?; + let cargs_list = cargs_list.downcast::().unwrap(); + let cargs_set = imports::BUILTIN_SET.get_bound(py).call1((cargs_list,))?; + let cargs_set = cargs_set.downcast::().unwrap(); + if !propagate_condition && self.may_have_additional_wires(py, &node) { + let (add_cargs, _add_vars) = + self.additional_wires(py, node.op.view(), node.condition())?; + for wire in add_cargs.iter() { + let clbit = &self.clbits.get(*wire).unwrap(); + if !cargs_set.contains(clbit.clone_ref(py))? { + cargs_list.append(clbit)?; + } + } + } + let qargs_len = qargs_list.len(); + let cargs_len = cargs_list.len(); + + if qargs_len + cargs_len != wires.len() { + return Err(DAGCircuitError::new_err(format!( + "bit mapping invalid: expected {}, got {}", + qargs_len + cargs_len, + wires.len() + ))); + } + let mut qubit_wire_map = HashMap::new(); + let mut clbit_wire_map = HashMap::new(); + let var_map = PyDict::new_bound(py); + for (index, wire) in wires.iter().enumerate() { + if wire.is_instance(imports::QUBIT.get_bound(py))? { + if index >= qargs_len { + unreachable!() + } + let input_qubit: Qubit = input_dag.qubits.find(&wire).unwrap(); + let self_qubit: Qubit = self.qubits.find(&qargs_list.get_item(index)?).unwrap(); + qubit_wire_map.insert(input_qubit, self_qubit); + } else if wire.is_instance(imports::CLBIT.get_bound(py))? { + if index < qargs_len { + unreachable!() + } + clbit_wire_map.insert( + input_dag.clbits.find(&wire).unwrap(), + self.clbits + .find(&cargs_list.get_item(index - qargs_len)?) + .unwrap(), + ); + } else { + return Err(DAGCircuitError::new_err( + "`Var` nodes cannot be remapped during substitution", + )); + } + } + Ok((qubit_wire_map, clbit_wire_map, var_map.unbind())) + }; + + let (mut qubit_wire_map, mut clbit_wire_map, var_map): ( + HashMap, + HashMap, + Py, + ) = match wires { + Some(wires) => match wires.downcast::() { + Ok(bound_wires) => { + let mut qubit_wire_map = HashMap::new(); + let mut clbit_wire_map = HashMap::new(); + let var_map = PyDict::new_bound(py); + for (source_wire, target_wire) in bound_wires.iter() { + if source_wire.is_instance(imports::QUBIT.get_bound(py))? { + qubit_wire_map.insert( + input_dag.qubits.find(&source_wire).unwrap(), + self.qubits.find(&target_wire).unwrap(), + ); + } else if source_wire.is_instance(imports::CLBIT.get_bound(py))? { + clbit_wire_map.insert( + input_dag.clbits.find(&source_wire).unwrap(), + self.clbits.find(&target_wire).unwrap(), + ); + } else { + var_map.set_item(source_wire, target_wire)?; + } + } + (qubit_wire_map, clbit_wire_map, var_map.unbind()) + } + Err(_) => { + let wires: Bound = match wires.downcast::() { + Ok(bound_list) => bound_list.clone(), + // If someone passes a sequence instead of an exact list (tuple is + // occasionally used) cast that to a list and then use it. + Err(_) => { + let raw_wires = imports::BUILTIN_LIST.get_bound(py).call1((wires,))?; + raw_wires.extract()? + } + }; + build_wire_map(&wires)? + } + }, + None => { + let raw_wires = input_dag.get_wires(py); + let binding = raw_wires?; + let wires = binding.bind(py); + build_wire_map(wires)? + } + }; + + let var_iter = input_dag.iter_vars(py)?; + let raw_set = imports::BUILTIN_SET.get_bound(py).call1((var_iter,))?; + let input_dag_var_set: &Bound = raw_set.downcast()?; + + let node_vars = if self.may_have_additional_wires(py, &node) { + let (_additional_clbits, additional_vars) = + self.additional_wires(py, node.op.view(), node.condition())?; + let var_set = PySet::new_bound(py, &additional_vars)?; + if input_dag_var_set + .call_method1(intern!(py, "difference"), (var_set.clone(),))? + .is_truthy()? + { + return Err(DAGCircuitError::new_err(format!( + "Cannot replace a node with a DAG with more variables. Variables in node: {:?}. Variables in dag: {:?}", + var_set.str(), input_dag_var_set.str(), + ))); + } + var_set + } else { + PySet::empty_bound(py)? + }; + let bound_var_map = var_map.bind(py); + for var in input_dag_var_set.iter() { + bound_var_map.set_item(var.clone(), var)?; + } + + for contracted_var in node_vars + .call_method1(intern!(py, "difference"), (input_dag_var_set,))? + .downcast::()? + .iter() + { + let pred = self + .dag + .edges_directed(node_index, Incoming) + .find(|edge| { + if let Wire::Var(var) = edge.weight() { + contracted_var.eq(var).unwrap() + } else { + false + } + }) + .unwrap(); + let succ = self + .dag + .edges_directed(node_index, Outgoing) + .find(|edge| { + if let Wire::Var(var) = edge.weight() { + contracted_var.eq(var).unwrap() + } else { + false + } + }) + .unwrap(); + self.dag.add_edge( + pred.source(), + succ.target(), + Wire::Var(contracted_var.unbind()), + ); + } + + let mut new_input_dag: Option = None; + // It doesn't make sense to try and propagate a condition from a control-flow op; a + // replacement for the control-flow op should implement the operation completely. + let node_map = if propagate_condition && !node.op.control_flow() { + // Nested until https://github.com/rust-lang/rust/issues/53667 is fixed in a stable + // release + if let Some(condition) = node + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()) + { + let mut in_dag = input_dag.copy_empty_like(py, "alike")?; + // The remapping of `condition` below is still using the old code that assumes a 2-tuple. + // This is because this remapping code only makes sense in the case of non-control-flow + // operations being replaced. These can only have the 2-tuple conditions, and the + // ability to set a condition at an individual node level will be deprecated and removed + // in favour of the new-style conditional blocks. The extra logic in here to add + // additional wires into the map as necessary would hugely complicate matters if we tried + // to abstract it out into the `VariableMapper` used elsewhere. + let wire_map = PyDict::new_bound(py); + for (source_qubit, target_qubit) in &qubit_wire_map { + wire_map.set_item( + in_dag.qubits.get(*source_qubit).unwrap().clone_ref(py), + self.qubits.get(*target_qubit).unwrap().clone_ref(py), + )? + } + for (source_clbit, target_clbit) in &clbit_wire_map { + wire_map.set_item( + in_dag.clbits.get(*source_clbit).unwrap().clone_ref(py), + self.clbits.get(*target_clbit).unwrap().clone_ref(py), + )? + } + wire_map.update(var_map.bind(py).as_mapping())?; + + let reverse_wire_map = wire_map.iter().map(|(k, v)| (v, k)).into_py_dict_bound(py); + let (py_target, py_value): (Bound, Bound) = + condition.bind(py).extract()?; + let (py_new_target, target_cargs) = + if py_target.is_instance(imports::CLBIT.get_bound(py))? { + let new_target = reverse_wire_map + .get_item(&py_target)? + .map(Ok::<_, PyErr>) + .unwrap_or_else(|| { + // Target was not in node's wires, so we need a dummy. + let new_target = imports::CLBIT.get_bound(py).call0()?; + in_dag.add_clbit_unchecked(py, &new_target)?; + wire_map.set_item(&new_target, &py_target)?; + reverse_wire_map.set_item(&py_target, &new_target)?; + Ok(new_target) + })?; + (new_target.clone(), PySet::new_bound(py, &[new_target])?) + } else { + // ClassicalRegister + let target_bits: Vec> = + py_target.iter()?.collect::>()?; + let mapped_bits: Vec>> = target_bits + .iter() + .map(|b| reverse_wire_map.get_item(b)) + .collect::>()?; + + let mut new_target = Vec::with_capacity(target_bits.len()); + let target_cargs = PySet::empty_bound(py)?; + for (ours, theirs) in target_bits.into_iter().zip(mapped_bits) { + if let Some(theirs) = theirs { + // Target bit was in node's wires. + new_target.push(theirs.clone()); + target_cargs.add(theirs)?; + } else { + // Target bit was not in node's wires, so we need a dummy. + let theirs = imports::CLBIT.get_bound(py).call0()?; + in_dag.add_clbit_unchecked(py, &theirs)?; + wire_map.set_item(&theirs, &ours)?; + reverse_wire_map.set_item(&ours, &theirs)?; + new_target.push(theirs.clone()); + target_cargs.add(theirs)?; + } + } + let kwargs = [("bits", new_target.into_py(py))].into_py_dict_bound(py); + let new_target_register = imports::CLASSICAL_REGISTER + .get_bound(py) + .call((), Some(&kwargs))?; + in_dag.add_creg(py, &new_target_register)?; + (new_target_register, target_cargs) + }; + let new_condition = PyTuple::new_bound(py, [py_new_target, py_value]); + + qubit_wire_map.clear(); + clbit_wire_map.clear(); + for item in wire_map.items().iter() { + let (in_bit, self_bit): (Bound, Bound) = item.extract()?; + if in_bit.is_instance(imports::QUBIT.get_bound(py))? { + let in_index = in_dag.qubits.find(&in_bit).unwrap(); + let self_index = self.qubits.find(&self_bit).unwrap(); + qubit_wire_map.insert(in_index, self_index); + } else { + let in_index = in_dag.clbits.find(&in_bit).unwrap(); + let self_index = self.clbits.find(&self_bit).unwrap(); + clbit_wire_map.insert(in_index, self_index); + } + } + for in_node_index in input_dag.topological_op_nodes()? { + let in_node = &input_dag.dag[in_node_index]; + if let NodeType::Operation(inst) = in_node { + if inst + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()) + .is_some() + { + return Err(DAGCircuitError::new_err( + "cannot propagate a condition to an element that already has one", + )); + } + let cargs = input_dag.cargs_cache.intern(inst.clbits); + let cargs_bits: Vec = input_dag + .clbits + .map_indices(cargs) + .map(|x| x.clone_ref(py)) + .collect(); + if !target_cargs + .call_method1(intern!(py, "intersection"), (cargs_bits,))? + .downcast::()? + .is_empty() + { + return Err(DAGCircuitError::new_err("cannot propagate a condition to an element that acts on those bits")); + } + let mut new_inst = inst.clone(); + if new_condition.is_truthy()? { + if let Some(ref mut attrs) = new_inst.extra_attrs { + attrs.condition = Some(new_condition.as_any().clone().unbind()); + } else { + new_inst.extra_attrs = Some(Box::new(ExtraInstructionAttributes { + condition: Some(new_condition.as_any().clone().unbind()), + label: None, + duration: None, + unit: None, + })); + } + #[cfg(feature = "cache_pygates")] + { + new_inst.py_op.take(); + } + } + in_dag.push_back(py, new_inst)?; + } + } + let node_map = self.substitute_node_with_subgraph( + py, + node_index, + &in_dag, + &qubit_wire_map, + &clbit_wire_map, + &var_map, + )?; + new_input_dag = Some(in_dag); + node_map + } else { + self.substitute_node_with_subgraph( + py, + node_index, + input_dag, + &qubit_wire_map, + &clbit_wire_map, + &var_map, + )? + } + } else { + self.substitute_node_with_subgraph( + py, + node_index, + input_dag, + &qubit_wire_map, + &clbit_wire_map, + &var_map, + )? + }; + self.global_phase = add_global_phase(py, &self.global_phase, &input_dag.global_phase)?; + + let wire_map_dict = PyDict::new_bound(py); + for (source, target) in clbit_wire_map.iter() { + let source_bit = match new_input_dag { + Some(ref in_dag) => in_dag.clbits.get(*source), + None => input_dag.clbits.get(*source), + }; + let target_bit = self.clbits.get(*target); + wire_map_dict.set_item(source_bit, target_bit)?; + } + let bound_var_map = var_map.bind(py); + + // Note: creating this list to hold new registers created by the mapper is a temporary + // measure until qiskit.expr is ported to Rust. It is necessary because we cannot easily + // have Python call back to DAGCircuit::add_creg while we're currently borrowing + // the DAGCircuit. + let new_registers = PyList::empty_bound(py); + let add_new_register = new_registers.getattr("append")?.unbind(); + let flush_new_registers = |dag: &mut DAGCircuit| -> PyResult<()> { + for reg in &new_registers { + dag.add_creg(py, ®)?; + } + new_registers.del_slice(0, new_registers.len())?; + Ok(()) + }; + + let variable_mapper = PyVariableMapper::new( + py, + self.cregs.bind(py).values().into_any(), + Some(wire_map_dict), + Some(bound_var_map.clone()), + Some(add_new_register), + )?; + + for (old_node_index, new_node_index) in node_map.iter() { + let old_node = match new_input_dag { + Some(ref in_dag) => &in_dag.dag[*old_node_index], + None => &input_dag.dag[*old_node_index], + }; + if let NodeType::Operation(old_inst) = old_node { + if let OperationRef::Instruction(old_op) = old_inst.op.view() { + if old_op.name() == "switch_case" { + let raw_target = old_op.instruction.getattr(py, "target")?; + let target = raw_target.bind(py); + let kwargs = PyDict::new_bound(py); + kwargs.set_item( + "label", + old_inst + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.label.as_ref()), + )?; + let new_op = imports::SWITCH_CASE_OP.get_bound(py).call( + ( + variable_mapper.map_target(target)?, + old_op.instruction.call_method0(py, "cases_specifier")?, + ), + Some(&kwargs), + )?; + flush_new_registers(self)?; + + if let NodeType::Operation(ref mut new_inst) = + &mut self.dag[*new_node_index] + { + new_inst.op = PyInstruction { + qubits: old_op.num_qubits(), + clbits: old_op.num_clbits(), + params: old_op.num_params(), + control_flow: old_op.control_flow(), + op_name: old_op.name().to_string(), + instruction: new_op.clone().unbind(), + } + .into(); + #[cfg(feature = "cache_pygates")] + { + new_inst.py_op = new_op.unbind().into(); + } + } + } + } + if let Some(condition) = old_inst + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()) + { + if old_inst.op.name() != "switch_case" { + let new_condition: Option = variable_mapper + .map_condition(condition.bind(py), false)? + .extract()?; + flush_new_registers(self)?; + + if let NodeType::Operation(ref mut new_inst) = + &mut self.dag[*new_node_index] + { + match &mut new_inst.extra_attrs { + Some(attrs) => attrs.condition.clone_from(&new_condition), + None => { + new_inst.extra_attrs = + Some(Box::new(ExtraInstructionAttributes { + label: None, + condition: new_condition.clone(), + unit: None, + duration: None, + })) + } + } + #[cfg(feature = "cache_pygates")] + { + new_inst.py_op.take(); + } + match new_inst.op.view() { + OperationRef::Instruction(py_inst) => { + py_inst + .instruction + .setattr(py, "condition", new_condition)?; + } + OperationRef::Gate(py_gate) => { + py_gate.gate.setattr(py, "condition", new_condition)?; + } + OperationRef::Operation(py_op) => { + py_op.operation.setattr(py, "condition", new_condition)?; + } + OperationRef::Standard(_) => {} + } + } + } + } + } + } + let out_dict = PyDict::new_bound(py); + for (old_index, new_index) in node_map { + out_dict.set_item(old_index.index(), self.get_node(py, new_index)?)?; + } + Ok(out_dict.unbind()) + } + + /// Replace a DAGOpNode with a single operation. qargs, cargs and + /// conditions for the new operation will be inferred from the node to be + /// replaced. The new operation will be checked to match the shape of the + /// replaced operation. + /// + /// Args: + /// node (DAGOpNode): Node to be replaced + /// op (qiskit.circuit.Operation): The :class:`qiskit.circuit.Operation` + /// instance to be added to the DAG + /// inplace (bool): Optional, default False. If True, existing DAG node + /// will be modified to include op. Otherwise, a new DAG node will + /// be used. + /// propagate_condition (bool): Optional, default True. If True, a condition on the + /// ``node`` to be replaced will be applied to the new ``op``. This is the legacy + /// behaviour. If either node is a control-flow operation, this will be ignored. If + /// the ``op`` already has a condition, :exc:`.DAGCircuitError` is raised. + /// + /// Returns: + /// DAGOpNode: the new node containing the added operation. + /// + /// Raises: + /// DAGCircuitError: If replacement operation was incompatible with + /// location of target node. + #[pyo3(signature = (node, op, inplace=false, propagate_condition=true))] + fn substitute_node( + &mut self, + node: &Bound, + op: &Bound, + inplace: bool, + propagate_condition: bool, + ) -> PyResult> { + let mut node: PyRefMut = match node.downcast() { + Ok(node) => node.borrow_mut(), + Err(_) => return Err(DAGCircuitError::new_err("Only DAGOpNodes can be replaced.")), + }; + let py = op.py(); + let node_index = node.as_ref().node.unwrap(); + // Extract information from node that is going to be replaced + let old_packed = match self.dag.node_weight(node_index) { + Some(NodeType::Operation(old_packed)) => old_packed.clone(), + Some(_) => { + return Err(DAGCircuitError::new_err( + "'node' must be of type 'DAGOpNode'.", + )) + } + None => return Err(DAGCircuitError::new_err("'node' not found in DAG.")), + }; + // Extract information from new op + let new_op = op.extract::()?; + let current_wires: HashSet = self + .dag + .edges(node_index) + .map(|e| e.weight().clone()) + .collect(); + let mut new_wires: HashSet = self + .qargs_cache + .intern(old_packed.qubits) + .iter() + .map(|x| Wire::Qubit(*x)) + .chain( + self.cargs_cache + .intern(old_packed.clbits) + .iter() + .map(|x| Wire::Clbit(*x)), + ) + .collect(); + let (additional_clbits, additional_vars) = self.additional_wires( + py, + new_op.operation.view(), + new_op + .extra_attrs + .as_ref() + .and_then(|attrs| attrs.condition.as_ref()), + )?; + new_wires.extend(additional_clbits.iter().map(|x| Wire::Clbit(*x))); + new_wires.extend(additional_vars.iter().map(|x| Wire::Var(x.clone_ref(py)))); + + if old_packed.op.num_qubits() != new_op.operation.num_qubits() + || old_packed.op.num_clbits() != new_op.operation.num_clbits() + { + return Err(DAGCircuitError::new_err( + format!( + "Cannot replace node of width ({} qubits, {} clbits) with operation of mismatched width ({} qubits, {} clbits)", + old_packed.op.num_qubits(), old_packed.op.num_clbits(), new_op.operation.num_qubits(), new_op.operation.num_clbits() + ))); + } + + #[cfg(feature = "cache_pygates")] + let mut py_op_cache = Some(op.clone().unbind()); + + let mut extra_attrs = new_op.extra_attrs.clone(); + // If either operation is a control-flow operation, propagate_condition is ignored + if propagate_condition + && !(node.instruction.operation.control_flow() || new_op.operation.control_flow()) + { + // if new_op has a condition, the condition can't be propagated from the old node + if new_op + .extra_attrs + .as_ref() + .and_then(|extra| extra.condition.as_ref()) + .is_some() + { + return Err(DAGCircuitError::new_err( + "Cannot propagate a condition to an operation that already has one.", + )); + } + if let Some(old_condition) = old_packed.condition() { + if matches!(new_op.operation.view(), OperationRef::Operation(_)) { + return Err(DAGCircuitError::new_err( + "Cannot add a condition on a generic Operation.", + )); + } + if let Some(ref mut extra) = extra_attrs { + extra.condition = Some(old_condition.clone_ref(py)); + } else { + extra_attrs = ExtraInstructionAttributes::new( + None, + None, + None, + Some(old_condition.clone_ref(py)), + ) + .map(Box::new) + } + let binding = self + .control_flow_module + .condition_resources(old_condition.bind(py))?; + let condition_clbits = binding.clbits.bind(py); + for bit in condition_clbits { + new_wires.insert(Wire::Clbit(self.clbits.find(&bit).unwrap())); + } + let op_ref = new_op.operation.view(); + if let OperationRef::Instruction(inst) = op_ref { + inst.instruction + .bind(py) + .setattr(intern!(py, "condition"), old_condition)?; + } else if let OperationRef::Gate(gate) = op_ref { + gate.gate.bind(py).call_method1( + intern!(py, "c_if"), + old_condition.downcast_bound::(py)?, + )?; + } + #[cfg(feature = "cache_pygates")] + { + py_op_cache = None; + } + } + }; + if new_wires != current_wires { + // The new wires must be a non-strict subset of the current wires; if they add new + // wires, we'd not know where to cut the existing wire to insert the new dependency. + return Err(DAGCircuitError::new_err(format!( + "New operation '{:?}' does not span the same wires as the old node '{:?}'. New wires: {:?}, old_wires: {:?}.", op.str(), old_packed.op.view(), new_wires, current_wires + ))); + } + + if inplace { + node.instruction.operation = new_op.operation.clone(); + node.instruction.params = new_op.params.clone(); + node.instruction.extra_attrs = extra_attrs.clone(); + #[cfg(feature = "cache_pygates")] + { + node.instruction.py_op = py_op_cache + .as_ref() + .map(|ob| OnceCell::from(ob.clone_ref(py))) + .unwrap_or_default(); + } + } + // Clone op data, as it will be moved into the PackedInstruction + let new_weight = NodeType::Operation(PackedInstruction { + op: new_op.operation.clone(), + qubits: old_packed.qubits, + clbits: old_packed.clbits, + params: (!new_op.params.is_empty()).then(|| new_op.params.into()), + extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op: py_op_cache.map(OnceCell::from).unwrap_or_default(), + }); + let node_index = node.as_ref().node.unwrap(); + if let Some(weight) = self.dag.node_weight_mut(node_index) { + *weight = new_weight; + } + + // Update self.op_names + self.decrement_op(old_packed.op.name()); + self.increment_op(new_op.operation.name()); + + if inplace { + Ok(node.into_py(py)) + } else { + self.get_node(py, node_index) + } + } + + /// Decompose the circuit into sets of qubits with no gates connecting them. + /// + /// Args: + /// remove_idle_qubits (bool): Flag denoting whether to remove idle qubits from + /// the separated circuits. If ``False``, each output circuit will contain the + /// same number of qubits as ``self``. + /// + /// Returns: + /// List[DAGCircuit]: The circuits resulting from separating ``self`` into sets + /// of disconnected qubits + /// + /// Each :class:`~.DAGCircuit` instance returned by this method will contain the same number of + /// clbits as ``self``. The global phase information in ``self`` will not be maintained + /// in the subcircuits returned by this method. + #[pyo3(signature = (remove_idle_qubits=false, *, vars_mode="alike"))] + fn separable_circuits( + &self, + py: Python, + remove_idle_qubits: bool, + vars_mode: &str, + ) -> PyResult> { + let connected_components = rustworkx_core::connectivity::connected_components(&self.dag); + let dags = PyList::empty_bound(py); + + for comp_nodes in connected_components.iter() { + let mut new_dag = self.copy_empty_like(py, vars_mode)?; + new_dag.global_phase = Param::Float(0.); + + // A map from nodes in the this DAGCircuit to nodes in the new dag. Used for adding edges + let mut node_map: HashMap = + HashMap::with_capacity(comp_nodes.len()); + + // Adding the nodes to the new dag + let mut non_classical = false; + for node in comp_nodes { + match self.dag.node_weight(*node) { + Some(w) => match w { + NodeType::ClbitIn(b) => { + let clbit_in = new_dag.clbit_io_map[b.0 as usize][0]; + node_map.insert(*node, clbit_in); + } + NodeType::ClbitOut(b) => { + let clbit_out = new_dag.clbit_io_map[b.0 as usize][1]; + node_map.insert(*node, clbit_out); + } + NodeType::QubitIn(q) => { + let qbit_in = new_dag.qubit_io_map[q.0 as usize][0]; + node_map.insert(*node, qbit_in); + non_classical = true; + } + NodeType::QubitOut(q) => { + let qbit_out = new_dag.qubit_io_map[q.0 as usize][1]; + node_map.insert(*node, qbit_out); + non_classical = true; + } + NodeType::VarIn(v) => { + let var_in = new_dag.var_input_map.get(py, v).unwrap(); + node_map.insert(*node, var_in); + } + NodeType::VarOut(v) => { + let var_out = new_dag.var_output_map.get(py, v).unwrap(); + node_map.insert(*node, var_out); + } + NodeType::Operation(pi) => { + let new_node = new_dag.dag.add_node(NodeType::Operation(pi.clone())); + new_dag.increment_op(pi.op.name()); + node_map.insert(*node, new_node); + non_classical = true; + } + }, + None => panic!("DAG node without payload!"), + } + } + if !non_classical { + continue; + } + let node_filter = |node: NodeIndex| -> bool { node_map.contains_key(&node) }; + + let filtered = NodeFiltered(&self.dag, node_filter); + + // Remove the edges added by copy_empty_like (as idle wires) to avoid duplication + new_dag.dag.clear_edges(); + for edge in filtered.edge_references() { + let new_source = node_map[&edge.source()]; + let new_target = node_map[&edge.target()]; + new_dag + .dag + .add_edge(new_source, new_target, edge.weight().clone()); + } + // Add back any edges for idle wires + for (qubit, [in_node, out_node]) in new_dag + .qubit_io_map + .iter() + .enumerate() + .map(|(idx, indices)| (Qubit(idx as u32), indices)) + { + if new_dag.dag.edges(*in_node).next().is_none() { + new_dag + .dag + .add_edge(*in_node, *out_node, Wire::Qubit(qubit)); + } + } + for (clbit, [in_node, out_node]) in new_dag + .clbit_io_map + .iter() + .enumerate() + .map(|(idx, indices)| (Clbit(idx as u32), indices)) + { + if new_dag.dag.edges(*in_node).next().is_none() { + new_dag + .dag + .add_edge(*in_node, *out_node, Wire::Clbit(clbit)); + } + } + for (var, in_node) in new_dag.var_input_map.iter(py) { + if new_dag.dag.edges(in_node).next().is_none() { + let out_node = new_dag.var_output_map.get(py, &var).unwrap(); + new_dag + .dag + .add_edge(in_node, out_node, Wire::Var(var.clone_ref(py))); + } + } + if remove_idle_qubits { + let idle_wires: Vec> = new_dag + .idle_wires(py, None)? + .into_bound(py) + .map(|q| q.unwrap()) + .filter(|e| e.is_instance(imports::QUBIT.get_bound(py)).unwrap()) + .collect(); + + let qubits = PyTuple::new_bound(py, idle_wires); + new_dag.remove_qubits(py, &qubits)?; // TODO: this does not really work, some issue with remove_qubits itself + } + + dags.append(pyo3::Py::new(py, new_dag)?)?; + } + + Ok(dags.unbind()) + } + + /// Swap connected nodes e.g. due to commutation. + /// + /// Args: + /// node1 (OpNode): predecessor node + /// node2 (OpNode): successor node + /// + /// Raises: + /// DAGCircuitError: if either node is not an OpNode or nodes are not connected + fn swap_nodes(&mut self, node1: &DAGNode, node2: &DAGNode) -> PyResult<()> { + let node1 = node1.node.unwrap(); + let node2 = node2.node.unwrap(); + + // Check that both nodes correspond to operations + if !matches!(self.dag.node_weight(node1).unwrap(), NodeType::Operation(_)) + || !matches!(self.dag.node_weight(node2).unwrap(), NodeType::Operation(_)) + { + return Err(DAGCircuitError::new_err( + "Nodes to swap are not both DAGOpNodes", + )); + } + + // Gather all wires connecting node1 and node2. + // This functionality was extracted from rustworkx's 'get_edge_data' + let wires: Vec = self + .dag + .edges(node1) + .filter(|edge| edge.target() == node2) + .map(|edge| edge.weight().clone()) + .collect(); + + if wires.is_empty() { + return Err(DAGCircuitError::new_err( + "Attempt to swap unconnected nodes", + )); + }; + + // Closure that finds the first parent/child node connected to a reference node by given wire + // and returns relevant edge information depending on the specified direction: + // - Incoming -> parent -> outputs (parent_edge_id, parent_source_node_id) + // - Outgoing -> child -> outputs (child_edge_id, child_target_node_id) + // This functionality was inspired in rustworkx's 'find_predecessors_by_edge' and 'find_successors_by_edge'. + let directed_edge_for_wire = |node: NodeIndex, direction: Direction, wire: &Wire| { + for edge in self.dag.edges_directed(node, direction) { + if wire == edge.weight() { + match direction { + Incoming => return Some((edge.id(), edge.source())), + Outgoing => return Some((edge.id(), edge.target())), + } + } + } + None + }; + + // Vector that contains a tuple of (wire, edge_info, parent_info, child_info) per wire in wires + let relevant_edges = wires + .iter() + .rev() + .map(|wire| { + ( + wire, + directed_edge_for_wire(node1, Outgoing, wire).unwrap(), + directed_edge_for_wire(node1, Incoming, wire).unwrap(), + directed_edge_for_wire(node2, Outgoing, wire).unwrap(), + ) + }) + .collect::>(); + + // Iterate over relevant edges and modify self.dag + for (wire, (node1_to_node2, _), (parent_to_node1, parent), (node2_to_child, child)) in + relevant_edges + { + self.dag.remove_edge(parent_to_node1); + self.dag.add_edge(parent, node2, wire.clone()); + self.dag.remove_edge(node1_to_node2); + self.dag.add_edge(node2, node1, wire.clone()); + self.dag.remove_edge(node2_to_child); + self.dag.add_edge(node1, child, wire.clone()); + } + Ok(()) + } + + /// Get the node in the dag. + /// + /// Args: + /// node_id(int): Node identifier. + /// + /// Returns: + /// node: the node. + fn node(&self, py: Python, node_id: isize) -> PyResult> { + self.get_node(py, NodeIndex::new(node_id as usize)) + } + + /// Iterator for node values. + /// + /// Yield: + /// node: the node. + fn nodes(&self, py: Python) -> PyResult> { + let result: PyResult> = self + .dag + .node_references() + .map(|(node, weight)| self.unpack_into(py, node, weight)) + .collect(); + let tup = PyTuple::new_bound(py, result?); + Ok(tup.into_any().iter().unwrap().unbind()) + } + + /// Iterator for edge values with source and destination node. + /// + /// This works by returning the outgoing edges from the specified nodes. If + /// no nodes are specified all edges from the graph are returned. + /// + /// Args: + /// nodes(DAGOpNode, DAGInNode, or DAGOutNode|list(DAGOpNode, DAGInNode, or DAGOutNode): + /// Either a list of nodes or a single input node. If none is specified, + /// all edges are returned from the graph. + /// + /// Yield: + /// edge: the edge as a tuple with the format + /// (source node, destination node, edge wire) + fn edges(&self, nodes: Option>, py: Python) -> PyResult> { + let get_node_index = |obj: &Bound| -> PyResult { + Ok(obj.downcast::()?.borrow().node.unwrap()) + }; + + let actual_nodes: Vec<_> = match nodes { + None => self.dag.node_indices().collect(), + Some(nodes) => { + let mut out = Vec::new(); + if let Ok(node) = get_node_index(&nodes) { + out.push(node); + } else { + for node in nodes.iter()? { + out.push(get_node_index(&node?)?); + } + } + out + } + }; + + let mut edges = Vec::new(); + for node in actual_nodes { + for edge in self.dag.edges_directed(node, Outgoing) { + edges.push(( + self.get_node(py, edge.source())?, + self.get_node(py, edge.target())?, + match edge.weight() { + Wire::Qubit(qubit) => self.qubits.get(*qubit).unwrap(), + Wire::Clbit(clbit) => self.clbits.get(*clbit).unwrap(), + Wire::Var(var) => var, + }, + )) + } + } + + Ok(PyTuple::new_bound(py, edges) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Get the list of "op" nodes in the dag. + /// + /// Args: + /// op (Type): :class:`qiskit.circuit.Operation` subclass op nodes to + /// return. If None, return all op nodes. + /// include_directives (bool): include `barrier`, `snapshot` etc. + /// + /// Returns: + /// list[DAGOpNode]: the list of node ids containing the given op. + #[pyo3(name= "op_nodes", signature=(op=None, include_directives=true))] + fn py_op_nodes( + &self, + py: Python, + op: Option<&Bound>, + include_directives: bool, + ) -> PyResult>> { + let mut nodes = Vec::new(); + let filter_is_nonstandard = if let Some(op) = op { + op.getattr(intern!(py, "_standard_gate")).ok().is_none() + } else { + true + }; + for (node, weight) in self.dag.node_references() { + if let NodeType::Operation(packed) = &weight { + if !include_directives && packed.op.directive() { + continue; + } + if let Some(op_type) = op { + // This middle catch is to avoid Python-space operation creation for most uses of + // `op`; we're usually just looking for control-flow ops, and standard gates + // aren't control-flow ops. + if !(filter_is_nonstandard && packed.op.try_standard_gate().is_some()) + && packed.op.py_op_is_instance(op_type)? + { + nodes.push(self.unpack_into(py, node, weight)?); + } + } else { + nodes.push(self.unpack_into(py, node, weight)?); + } + } + } + Ok(nodes) + } + + /// Get the list of gate nodes in the dag. + /// + /// Returns: + /// list[DAGOpNode]: the list of DAGOpNodes that represent gates. + fn gate_nodes(&self, py: Python) -> PyResult>> { + self.dag + .node_references() + .filter_map(|(node, weight)| match weight { + NodeType::Operation(ref packed) => match packed.op.view() { + OperationRef::Gate(_) | OperationRef::Standard(_) => { + Some(self.unpack_into(py, node, weight)) + } + _ => None, + }, + _ => None, + }) + .collect() + } + + /// Get the set of "op" nodes with the given name. + #[pyo3(signature = (*names))] + fn named_nodes(&self, py: Python<'_>, names: &Bound) -> PyResult>> { + let mut names_set: HashSet = HashSet::with_capacity(names.len()); + for name_obj in names.iter() { + names_set.insert(name_obj.extract::()?); + } + let mut result: Vec> = Vec::new(); + for (id, weight) in self.dag.node_references() { + if let NodeType::Operation(ref packed) = weight { + if names_set.contains(packed.op.name()) { + result.push(self.unpack_into(py, id, weight)?); + } + } + } + Ok(result) + } + + /// Get list of 2 qubit operations. Ignore directives like snapshot and barrier. + fn two_qubit_ops(&self, py: Python) -> PyResult>> { + let mut nodes = Vec::new(); + for (node, weight) in self.dag.node_references() { + if let NodeType::Operation(ref packed) = weight { + if packed.op.directive() { + continue; + } + + let qargs = self.qargs_cache.intern(packed.qubits); + if qargs.len() == 2 { + nodes.push(self.unpack_into(py, node, weight)?); + } + } + } + Ok(nodes) + } + + /// Get list of 3+ qubit operations. Ignore directives like snapshot and barrier. + fn multi_qubit_ops(&self, py: Python) -> PyResult>> { + let mut nodes = Vec::new(); + for (node, weight) in self.dag.node_references() { + if let NodeType::Operation(ref packed) = weight { + if packed.op.directive() { + continue; + } + + let qargs = self.qargs_cache.intern(packed.qubits); + if qargs.len() >= 3 { + nodes.push(self.unpack_into(py, node, weight)?); + } + } + } + Ok(nodes) + } + + /// Returns the longest path in the dag as a list of DAGOpNodes, DAGInNodes, and DAGOutNodes. + fn longest_path(&self, py: Python) -> PyResult> { + let weight_fn = |_| -> Result { Ok(1) }; + match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { + Some(res) => res.0, + None => return Err(DAGCircuitError::new_err("not a DAG")), + } + .into_iter() + .map(|node_index| self.get_node(py, node_index)) + .collect() + } + + /// Returns iterator of the successors of a node as DAGOpNodes and DAGOutNodes.""" + fn successors(&self, py: Python, node: &DAGNode) -> PyResult> { + let successors: PyResult> = self + .dag + .neighbors_directed(node.node.unwrap(), Outgoing) + .unique() + .map(|i| self.get_node(py, i)) + .collect(); + Ok(PyTuple::new_bound(py, successors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Returns iterator of the predecessors of a node as DAGOpNodes and DAGInNodes. + fn predecessors(&self, py: Python, node: &DAGNode) -> PyResult> { + let predecessors: PyResult> = self + .dag + .neighbors_directed(node.node.unwrap(), Incoming) + .unique() + .map(|i| self.get_node(py, i)) + .collect(); + Ok(PyTuple::new_bound(py, predecessors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Returns iterator of "op" successors of a node in the dag. + fn op_successors(&self, py: Python, node: &DAGNode) -> PyResult> { + let predecessors: PyResult> = self + .dag + .neighbors_directed(node.node.unwrap(), Outgoing) + .unique() + .filter_map(|i| match self.dag[i] { + NodeType::Operation(_) => Some(self.get_node(py, i)), + _ => None, + }) + .collect(); + Ok(PyTuple::new_bound(py, predecessors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Returns the iterator of "op" predecessors of a node in the dag. + fn op_predecessors(&self, py: Python, node: &DAGNode) -> PyResult> { + let predecessors: PyResult> = self + .dag + .neighbors_directed(node.node.unwrap(), Incoming) + .unique() + .filter_map(|i| match self.dag[i] { + NodeType::Operation(_) => Some(self.get_node(py, i)), + _ => None, + }) + .collect(); + Ok(PyTuple::new_bound(py, predecessors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Checks if a second node is in the successors of node. + fn is_successor(&self, node: &DAGNode, node_succ: &DAGNode) -> bool { + self.dag + .find_edge(node.node.unwrap(), node_succ.node.unwrap()) + .is_some() + } + + /// Checks if a second node is in the predecessors of node. + fn is_predecessor(&self, node: &DAGNode, node_pred: &DAGNode) -> bool { + self.dag + .find_edge(node_pred.node.unwrap(), node.node.unwrap()) + .is_some() + } + + /// Returns iterator of the predecessors of a node that are + /// connected by a quantum edge as DAGOpNodes and DAGInNodes. + #[pyo3(name = "quantum_predecessors")] + fn py_quantum_predecessors(&self, py: Python, node: &DAGNode) -> PyResult> { + let predecessors: PyResult> = self + .quantum_predecessors(node.node.unwrap()) + .map(|i| self.get_node(py, i)) + .collect(); + Ok(PyTuple::new_bound(py, predecessors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Returns iterator of the successors of a node that are + /// connected by a quantum edge as DAGOpNodes and DAGOutNodes. + #[pyo3(name = "quantum_successors")] + fn py_quantum_successors(&self, py: Python, node: &DAGNode) -> PyResult> { + let successors: PyResult> = self + .quantum_successors(node.node.unwrap()) + .map(|i| self.get_node(py, i)) + .collect(); + Ok(PyTuple::new_bound(py, successors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Returns iterator of the predecessors of a node that are + /// connected by a classical edge as DAGOpNodes and DAGInNodes. + fn classical_predecessors(&self, py: Python, node: &DAGNode) -> PyResult> { + let edges = self.dag.edges_directed(node.node.unwrap(), Incoming); + let filtered = edges.filter_map(|e| match e.weight() { + Wire::Qubit(_) => None, + _ => Some(e.source()), + }); + let predecessors: PyResult> = + filtered.unique().map(|i| self.get_node(py, i)).collect(); + Ok(PyTuple::new_bound(py, predecessors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Returns set of the ancestors of a node as DAGOpNodes and DAGInNodes. + #[pyo3(name = "ancestors")] + fn py_ancestors(&self, py: Python, node: &DAGNode) -> PyResult> { + let ancestors: PyResult> = self + .ancestors(node.node.unwrap()) + .map(|node| self.get_node(py, node)) + .collect(); + Ok(PySet::new_bound(py, &ancestors?)?.unbind()) + } + + /// Returns set of the descendants of a node as DAGOpNodes and DAGOutNodes. + #[pyo3(name = "descendants")] + fn py_descendants(&self, py: Python, node: &DAGNode) -> PyResult> { + let descendants: PyResult> = self + .descendants(node.node.unwrap()) + .map(|node| self.get_node(py, node)) + .collect(); + Ok(PySet::new_bound(py, &descendants?)?.unbind()) + } + + /// Returns an iterator of tuples of (DAGNode, [DAGNodes]) where the DAGNode is the current node + /// and [DAGNode] is its successors in BFS order. + #[pyo3(name = "bfs_successors")] + fn py_bfs_successors(&self, py: Python, node: &DAGNode) -> PyResult> { + let successor_index: PyResult)>> = self + .bfs_successors(node.node.unwrap()) + .map(|(node, nodes)| -> PyResult<(PyObject, Vec)> { + Ok(( + self.get_node(py, node)?, + nodes + .iter() + .map(|sub_node| self.get_node(py, *sub_node)) + .collect::>>()?, + )) + }) + .collect(); + Ok(PyList::new_bound(py, successor_index?) + .into_any() + .iter()? + .unbind()) + } + + /// Returns iterator of the successors of a node that are + /// connected by a classical edge as DAGOpNodes and DAGOutNodes. + fn classical_successors(&self, py: Python, node: &DAGNode) -> PyResult> { + let edges = self.dag.edges_directed(node.node.unwrap(), Outgoing); + let filtered = edges.filter_map(|e| match e.weight() { + Wire::Qubit(_) => None, + _ => Some(e.target()), + }); + let predecessors: PyResult> = + filtered.unique().map(|i| self.get_node(py, i)).collect(); + Ok(PyTuple::new_bound(py, predecessors?) + .into_any() + .iter() + .unwrap() + .unbind()) + } + + /// Remove an operation node n. + /// + /// Add edges from predecessors to successors. + #[pyo3(name = "remove_op_node")] + fn py_remove_op_node(&mut self, node: &Bound) -> PyResult<()> { + let node: PyRef = match node.downcast::() { + Ok(node) => node.borrow(), + Err(_) => return Err(DAGCircuitError::new_err("Node not an DAGOpNode")), + }; + let index = node.as_ref().node.unwrap(); + if self.dag.node_weight(index).is_none() { + return Err(DAGCircuitError::new_err("Node not in DAG")); + } + self.remove_op_node(index); + Ok(()) + } + + /// Remove all of the ancestor operation nodes of node. + fn remove_ancestors_of(&mut self, node: &DAGNode) -> PyResult<()> { + let ancestors: Vec<_> = core_ancestors(&self.dag, node.node.unwrap()) + .filter(|next| { + next != &node.node.unwrap() + && matches!(self.dag.node_weight(*next), Some(NodeType::Operation(_))) + }) + .collect(); + for a in ancestors { + self.dag.remove_node(a); + } + Ok(()) + } + + /// Remove all of the descendant operation nodes of node. + fn remove_descendants_of(&mut self, node: &DAGNode) -> PyResult<()> { + let descendants: Vec<_> = core_descendants(&self.dag, node.node.unwrap()) + .filter(|next| { + next != &node.node.unwrap() + && matches!(self.dag.node_weight(*next), Some(NodeType::Operation(_))) + }) + .collect(); + for d in descendants { + self.dag.remove_node(d); + } + Ok(()) + } + + /// Remove all of the non-ancestors operation nodes of node. + fn remove_nonancestors_of(&mut self, node: &DAGNode) -> PyResult<()> { + let ancestors: HashSet<_> = core_ancestors(&self.dag, node.node.unwrap()) + .filter(|next| { + next != &node.node.unwrap() + && matches!(self.dag.node_weight(*next), Some(NodeType::Operation(_))) + }) + .collect(); + let non_ancestors: Vec<_> = self + .dag + .node_indices() + .filter(|node_id| !ancestors.contains(node_id)) + .collect(); + for na in non_ancestors { + self.dag.remove_node(na); + } + Ok(()) + } + + /// Remove all of the non-descendants operation nodes of node. + fn remove_nondescendants_of(&mut self, node: &DAGNode) -> PyResult<()> { + let descendants: HashSet<_> = core_descendants(&self.dag, node.node.unwrap()) + .filter(|next| { + next != &node.node.unwrap() + && matches!(self.dag.node_weight(*next), Some(NodeType::Operation(_))) + }) + .collect(); + let non_descendants: Vec<_> = self + .dag + .node_indices() + .filter(|node_id| !descendants.contains(node_id)) + .collect(); + for nd in non_descendants { + self.dag.remove_node(nd); + } + Ok(()) + } + + /// Return a list of op nodes in the first layer of this dag. + #[pyo3(name = "front_layer")] + fn py_front_layer(&self, py: Python) -> PyResult> { + let native_front_layer = self.front_layer(py); + let front_layer_list = PyList::empty_bound(py); + for node in native_front_layer { + front_layer_list.append(self.get_node(py, node)?)?; + } + Ok(front_layer_list.into()) + } + + /// Yield a shallow view on a layer of this DAGCircuit for all d layers of this circuit. + /// + /// A layer is a circuit whose gates act on disjoint qubits, i.e., + /// a layer has depth 1. The total number of layers equals the + /// circuit depth d. The layers are indexed from 0 to d-1 with the + /// earliest layer at index 0. The layers are constructed using a + /// greedy algorithm. Each returned layer is a dict containing + /// {"graph": circuit graph, "partition": list of qubit lists}. + /// + /// The returned layer contains new (but semantically equivalent) DAGOpNodes, DAGInNodes, + /// and DAGOutNodes. These are not the same as nodes of the original dag, but are equivalent + /// via DAGNode.semantic_eq(node1, node2). + /// + /// TODO: Gates that use the same cbits will end up in different + /// layers as this is currently implemented. This may not be + /// the desired behavior. + #[pyo3(signature = (*, vars_mode="captures"))] + fn layers(&self, py: Python, vars_mode: &str) -> PyResult> { + let layer_list = PyList::empty_bound(py); + let mut graph_layers = self.multigraph_layers(py); + if graph_layers.next().is_none() { + return Ok(PyIterator::from_bound_object(&layer_list)?.into()); + } + + for graph_layer in graph_layers { + let layer_dict = PyDict::new_bound(py); + // Sort to make sure they are in the order they were added to the original DAG + // It has to be done by node_id as graph_layer is just a list of nodes + // with no implied topology + // Drawing tools rely on _node_id to infer order of node creation + // so we need this to be preserved by layers() + // Get the op nodes from the layer, removing any input and output nodes. + let mut op_nodes: Vec<(&PackedInstruction, &NodeIndex)> = graph_layer + .iter() + .filter_map(|node| self.dag.node_weight(*node).map(|dag_node| (dag_node, node))) + .filter_map(|(node, index)| match node { + NodeType::Operation(oper) => Some((oper, index)), + _ => None, + }) + .collect(); + op_nodes.sort_by_key(|(_, node_index)| **node_index); + + if op_nodes.is_empty() { + return Ok(PyIterator::from_bound_object(&layer_list)?.into()); + } + + let mut new_layer = self.copy_empty_like(py, vars_mode)?; + + for (node, _) in op_nodes { + new_layer.push_back(py, node.clone())?; + } + + let new_layer_op_nodes = new_layer.op_nodes(false).filter_map(|node_index| { + match new_layer.dag.node_weight(node_index) { + Some(NodeType::Operation(ref node)) => Some(node), + _ => None, + } + }); + let support_iter = new_layer_op_nodes.into_iter().map(|node| { + PyTuple::new_bound( + py, + new_layer + .qubits + .map_indices(new_layer.qargs_cache.intern(node.qubits)), + ) + }); + let support_list = PyList::empty_bound(py); + for support_qarg in support_iter { + support_list.append(support_qarg)?; + } + layer_dict.set_item("graph", new_layer.into_py(py))?; + layer_dict.set_item("partition", support_list)?; + layer_list.append(layer_dict)?; + } + Ok(layer_list.into_any().iter()?.into()) + } + + /// Yield a layer for all gates of this circuit. + /// + /// A serial layer is a circuit with one gate. The layers have the + /// same structure as in layers(). + #[pyo3(signature = (*, vars_mode="captures"))] + fn serial_layers(&self, py: Python, vars_mode: &str) -> PyResult> { + let layer_list = PyList::empty_bound(py); + for next_node in self.topological_op_nodes()? { + let retrieved_node: &PackedInstruction = match self.dag.node_weight(next_node) { + Some(NodeType::Operation(node)) => node, + _ => unreachable!("A non-operation node was obtained from topological_op_nodes."), + }; + let mut new_layer = self.copy_empty_like(py, vars_mode)?; + + // Save the support of the operation we add to the layer + let support_list = PyList::empty_bound(py); + let qubits = PyTuple::new_bound( + py, + self.qargs_cache + .intern(retrieved_node.qubits) + .iter() + .map(|qubit| self.qubits.get(*qubit)), + ) + .unbind(); + new_layer.push_back(py, retrieved_node.clone())?; + + if !retrieved_node.op.directive() { + support_list.append(qubits)?; + } + + let layer_dict = [ + ("graph", new_layer.into_py(py)), + ("partition", support_list.into_any().unbind()), + ] + .into_py_dict_bound(py); + layer_list.append(layer_dict)?; + } + + Ok(layer_list.into_any().iter()?.into()) + } + + /// Yield layers of the multigraph. + #[pyo3(name = "multigraph_layers")] + fn py_multigraph_layers(&self, py: Python) -> PyResult> { + let graph_layers = self.multigraph_layers(py).map(|layer| -> Vec { + layer + .into_iter() + .filter_map(|index| self.get_node(py, index).ok()) + .collect() + }); + let list: Bound = + PyList::new_bound(py, graph_layers.collect::>>()); + Ok(PyIterator::from_bound_object(&list)?.unbind()) + } + + /// Return a set of non-conditional runs of "op" nodes with the given names. + /// + /// For example, "... h q[0]; cx q[0],q[1]; cx q[0],q[1]; h q[1]; .." + /// would produce the tuple of cx nodes as an element of the set returned + /// from a call to collect_runs(["cx"]). If instead the cx nodes were + /// "cx q[0],q[1]; cx q[1],q[0];", the method would still return the + /// pair in a tuple. The namelist can contain names that are not + /// in the circuit's basis. + /// + /// Nodes must have only one successor to continue the run. + #[pyo3(name = "collect_runs")] + fn py_collect_runs(&self, py: Python, namelist: &Bound) -> PyResult> { + let mut name_list_set = HashSet::with_capacity(namelist.len()); + for name in namelist.iter() { + name_list_set.insert(name.extract::()?); + } + match self.collect_runs(name_list_set) { + Some(runs) => { + let run_iter = runs.map(|node_indices| { + PyTuple::new_bound( + py, + node_indices + .into_iter() + .map(|node_index| self.get_node(py, node_index).unwrap()), + ) + .unbind() + }); + let out_set = PySet::empty_bound(py)?; + for run_tuple in run_iter { + out_set.add(run_tuple)?; + } + Ok(out_set.unbind()) + } + None => Err(PyRuntimeError::new_err( + "Invalid DAGCircuit, cycle encountered", + )), + } + } + + /// Return a set of non-conditional runs of 1q "op" nodes. + #[pyo3(name = "collect_1q_runs")] + fn py_collect_1q_runs(&self, py: Python) -> PyResult> { + match self.collect_1q_runs() { + Some(runs) => { + let runs_iter = runs.map(|node_indices| { + PyList::new_bound( + py, + node_indices + .into_iter() + .map(|node_index| self.get_node(py, node_index).unwrap()), + ) + .unbind() + }); + let out_list = PyList::empty_bound(py); + for run_list in runs_iter { + out_list.append(run_list)?; + } + Ok(out_list.unbind()) + } + None => Err(PyRuntimeError::new_err( + "Invalid DAGCircuit, cycle encountered", + )), + } + } + + /// Return a set of non-conditional runs of 2q "op" nodes. + #[pyo3(name = "collect_2q_runs")] + fn py_collect_2q_runs(&self, py: Python) -> PyResult> { + match self.collect_2q_runs() { + Some(runs) => { + let runs_iter = runs.into_iter().map(|node_indices| { + PyList::new_bound( + py, + node_indices + .into_iter() + .map(|node_index| self.get_node(py, node_index).unwrap()), + ) + .unbind() + }); + let out_list = PyList::empty_bound(py); + for run_list in runs_iter { + out_list.append(run_list)?; + } + Ok(out_list.unbind()) + } + None => Err(PyRuntimeError::new_err( + "Invalid DAGCircuit, cycle encountered", + )), + } + } + + /// Iterator for nodes that affect a given wire. + /// + /// Args: + /// wire (Bit): the wire to be looked at. + /// only_ops (bool): True if only the ops nodes are wanted; + /// otherwise, all nodes are returned. + /// Yield: + /// Iterator: the successive nodes on the given wire + /// + /// Raises: + /// DAGCircuitError: if the given wire doesn't exist in the DAG + #[pyo3(name = "nodes_on_wire", signature = (wire, only_ops=false))] + fn py_nodes_on_wire( + &self, + py: Python, + wire: &Bound, + only_ops: bool, + ) -> PyResult> { + let wire = if wire.is_instance(imports::QUBIT.get_bound(py))? { + self.qubits.find(wire).map(Wire::Qubit) + } else if wire.is_instance(imports::CLBIT.get_bound(py))? { + self.clbits.find(wire).map(Wire::Clbit) + } else if self.var_input_map.contains_key(py, &wire.clone().unbind()) { + Some(Wire::Var(wire.clone().unbind())) + } else { + None + } + .ok_or_else(|| { + DAGCircuitError::new_err(format!( + "The given wire {:?} is not present in the circuit", + wire + )) + })?; + + let nodes = self + .nodes_on_wire(py, &wire, only_ops) + .into_iter() + .map(|n| self.get_node(py, n)) + .collect::>>()?; + Ok(PyTuple::new_bound(py, nodes).into_any().iter()?.unbind()) + } + + /// Count the occurrences of operation names. + /// + /// Args: + /// recurse: if ``True`` (default), then recurse into control-flow operations. In all + /// cases, this counts only the number of times the operation appears in any possible + /// block; both branches of if-elses are counted, and for- and while-loop blocks are + /// only counted once. + /// + /// Returns: + /// Mapping[str, int]: a mapping of operation names to the number of times it appears. + #[pyo3(signature = (*, recurse=true))] + fn count_ops(&self, py: Python, recurse: bool) -> PyResult { + if !recurse + || !CONTROL_FLOW_OP_NAMES + .iter() + .any(|x| self.op_names.contains_key(*x)) + { + Ok(self.op_names.to_object(py)) + } else { + fn inner( + py: Python, + dag: &DAGCircuit, + counts: &mut HashMap, + ) -> PyResult<()> { + for (key, value) in dag.op_names.iter() { + counts + .entry(key.clone()) + .and_modify(|count| *count += value) + .or_insert(*value); + } + let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); + for node in dag.py_op_nodes( + py, + Some(imports::CONTROL_FLOW_OP.get_bound(py).downcast()?), + true, + )? { + let raw_blocks = node.getattr(py, "op")?.getattr(py, "blocks")?; + let blocks: &Bound = raw_blocks.downcast_bound::(py)?; + for block in blocks.iter() { + let inner_dag: &DAGCircuit = + &circuit_to_dag.call1((block.clone(),))?.extract()?; + inner(py, inner_dag, counts)?; + } + } + Ok(()) + } + let mut counts = HashMap::with_capacity(self.op_names.len()); + inner(py, self, &mut counts)?; + Ok(counts.to_object(py)) + } + } + + /// Count the occurrences of operation names on the longest path. + /// + /// Returns a dictionary of counts keyed on the operation name. + fn count_ops_longest_path(&self) -> PyResult> { + if self.dag.node_count() == 0 { + return Ok(HashMap::new()); + } + let weight_fn = |_| -> Result { Ok(1) }; + let longest_path = + match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { + Some(res) => res.0, + None => return Err(DAGCircuitError::new_err("not a DAG")), + }; + // Allocate for worst case where all operations are unique + let mut op_counts: HashMap<&str, usize> = HashMap::with_capacity(longest_path.len() - 2); + for node_index in &longest_path[1..longest_path.len() - 1] { + if let NodeType::Operation(ref packed) = self.dag[*node_index] { + let name = packed.op.name(); + op_counts + .entry(name) + .and_modify(|count| *count += 1) + .or_insert(1); + } + } + Ok(op_counts) + } + + /// Returns causal cone of a qubit. + /// + /// A qubit's causal cone is the set of qubits that can influence the output of that + /// qubit through interactions, whether through multi-qubit gates or operations. Knowing + /// the causal cone of a qubit can be useful when debugging faulty circuits, as it can + /// help identify which wire(s) may be causing the problem. + /// + /// This method does not consider any classical data dependency in the ``DAGCircuit``, + /// classical bit wires are ignored for the purposes of building the causal cone. + /// + /// Args: + /// qubit (~qiskit.circuit.Qubit): The output qubit for which we want to find the causal cone. + /// + /// Returns: + /// Set[~qiskit.circuit.Qubit]: The set of qubits whose interactions affect ``qubit``. + fn quantum_causal_cone(&self, py: Python, qubit: &Bound) -> PyResult> { + // Retrieve the output node from the qubit + let output_qubit = self.qubits.find(qubit).ok_or_else(|| { + DAGCircuitError::new_err(format!( + "The given qubit {:?} is not present in the circuit", + qubit + )) + })?; + let output_node_index = self + .qubit_io_map + .get(output_qubit.0 as usize) + .map(|x| x[1]) + .ok_or_else(|| { + DAGCircuitError::new_err(format!( + "The given qubit {:?} is not present in qubit_output_map", + qubit + )) + })?; + + let mut qubits_in_cone: HashSet<&Qubit> = HashSet::from([&output_qubit]); + let mut queue: VecDeque = self.quantum_predecessors(output_node_index).collect(); + + // The processed_non_directive_nodes stores the set of processed non-directive nodes. + // This is an optimization to avoid considering the same non-directive node multiple + // times when reached from different paths. + // The directive nodes (such as barriers or measures) are trickier since when processing + // them we only add their predecessors that intersect qubits_in_cone. Hence, directive + // nodes have to be considered multiple times. + let mut processed_non_directive_nodes: HashSet = HashSet::new(); + + while !queue.is_empty() { + let cur_index = queue.pop_front().unwrap(); + + if let NodeType::Operation(packed) = self.dag.node_weight(cur_index).unwrap() { + if !packed.op.directive() { + // If the operation is not a directive (in particular not a barrier nor a measure), + // we do not do anything if it was already processed. Otherwise, we add its qubits + // to qubits_in_cone, and append its predecessors to queue. + if processed_non_directive_nodes.contains(&cur_index) { + continue; + } + qubits_in_cone.extend(self.qargs_cache.intern(packed.qubits).iter()); + processed_non_directive_nodes.insert(cur_index); + + for pred_index in self.quantum_predecessors(cur_index) { + if let NodeType::Operation(_pred_packed) = + self.dag.node_weight(pred_index).unwrap() + { + queue.push_back(pred_index); + } + } + } else { + // Directives (such as barriers and measures) may be defined over all the qubits, + // yet not all of these qubits should be considered in the causal cone. So we + // only add those predecessors that have qubits in common with qubits_in_cone. + for pred_index in self.quantum_predecessors(cur_index) { + if let NodeType::Operation(pred_packed) = + self.dag.node_weight(pred_index).unwrap() + { + if self + .qargs_cache + .intern(pred_packed.qubits) + .iter() + .any(|x| qubits_in_cone.contains(x)) + { + queue.push_back(pred_index); + } + } + } + } + } + } + + let qubits_in_cone_vec: Vec<_> = qubits_in_cone.iter().map(|&&qubit| qubit).collect(); + let elements = self.qubits.map_indices(&qubits_in_cone_vec[..]); + Ok(PySet::new_bound(py, elements)?.unbind()) + } + + /// Return a dictionary of circuit properties. + fn properties(&self, py: Python) -> PyResult> { + Ok(HashMap::from_iter([ + ("size", self.size(py, false)?.into_py(py)), + ("depth", self.depth(py, false)?.into_py(py)), + ("width", self.width().into_py(py)), + ("qubits", self.num_qubits().into_py(py)), + ("bits", self.num_clbits().into_py(py)), + ("factors", self.num_tensor_factors().into_py(py)), + ("operations", self.count_ops(py, true)?), + ])) + } + + /// Draws the dag circuit. + /// + /// This function needs `Graphviz `_ to be + /// installed. Graphviz is not a python package and can't be pip installed + /// (the ``graphviz`` package on PyPI is a Python interface library for + /// Graphviz and does not actually install Graphviz). You can refer to + /// `the Graphviz documentation `__ on + /// how to install it. + /// + /// Args: + /// scale (float): scaling factor + /// filename (str): file path to save image to (format inferred from name) + /// style (str): + /// 'plain': B&W graph; + /// 'color' (default): color input/output/op nodes + /// + /// Returns: + /// Ipython.display.Image: if in Jupyter notebook and not saving to file, + /// otherwise None. + #[pyo3(signature=(scale=0.7, filename=None, style="color"))] + fn draw<'py>( + slf: PyRef<'py, Self>, + py: Python<'py>, + scale: f64, + filename: Option<&str>, + style: &str, + ) -> PyResult> { + let module = PyModule::import_bound(py, "qiskit.visualization.dag_visualization")?; + module.call_method1("dag_drawer", (slf, scale, filename, style)) + } + + fn _to_dot<'py>( + &self, + py: Python<'py>, + graph_attrs: Option>, + node_attrs: Option, + edge_attrs: Option, + ) -> PyResult> { + let mut buffer = Vec::::new(); + build_dot(py, self, &mut buffer, graph_attrs, node_attrs, edge_attrs)?; + Ok(PyString::new_bound(py, std::str::from_utf8(&buffer)?)) + } + + /// Add an input variable to the circuit. + /// + /// Args: + /// var: the variable to add. + fn add_input_var(&mut self, py: Python, var: &Bound) -> PyResult<()> { + if !self.vars_by_type[DAGVarType::Capture as usize] + .bind(py) + .is_empty() + { + return Err(DAGCircuitError::new_err( + "cannot add inputs to a circuit with captures", + )); + } + self.add_var(py, var, DAGVarType::Input) + } + + /// Add a captured variable to the circuit. + /// + /// Args: + /// var: the variable to add. + fn add_captured_var(&mut self, py: Python, var: &Bound) -> PyResult<()> { + if !self.vars_by_type[DAGVarType::Input as usize] + .bind(py) + .is_empty() + { + return Err(DAGCircuitError::new_err( + "cannot add captures to a circuit with inputs", + )); + } + self.add_var(py, var, DAGVarType::Capture) + } + + /// Add a declared local variable to the circuit. + /// + /// Args: + /// var: the variable to add. + fn add_declared_var(&mut self, py: Python, var: &Bound) -> PyResult<()> { + self.add_var(py, var, DAGVarType::Declare) + } + + /// Total number of classical variables tracked by the circuit. + #[getter] + fn num_vars(&self) -> usize { + self.vars_info.len() + } + + /// Number of input classical variables tracked by the circuit. + #[getter] + fn num_input_vars(&self, py: Python) -> usize { + self.vars_by_type[DAGVarType::Input as usize].bind(py).len() + } + + /// Number of captured classical variables tracked by the circuit. + #[getter] + fn num_captured_vars(&self, py: Python) -> usize { + self.vars_by_type[DAGVarType::Capture as usize] + .bind(py) + .len() + } + + /// Number of declared local classical variables tracked by the circuit. + #[getter] + fn num_declared_vars(&self, py: Python) -> usize { + self.vars_by_type[DAGVarType::Declare as usize] + .bind(py) + .len() + } + + /// Is this realtime variable in the DAG? + /// + /// Args: + /// var: the variable or name to check. + fn has_var(&self, var: &Bound) -> PyResult { + match var.extract::() { + Ok(name) => Ok(self.vars_info.contains_key(&name)), + Err(_) => { + let raw_name = var.getattr("name")?; + let var_name: String = raw_name.extract()?; + match self.vars_info.get(&var_name) { + Some(var_in_dag) => Ok(var_in_dag.var.is(var)), + None => Ok(false), + } + } + } + } + + /// Iterable over the input classical variables tracked by the circuit. + fn iter_input_vars(&self, py: Python) -> PyResult> { + Ok(self.vars_by_type[DAGVarType::Input as usize] + .bind(py) + .clone() + .into_any() + .iter()? + .unbind()) + } + + /// Iterable over the captured classical variables tracked by the circuit. + fn iter_captured_vars(&self, py: Python) -> PyResult> { + Ok(self.vars_by_type[DAGVarType::Capture as usize] + .bind(py) + .clone() + .into_any() + .iter()? + .unbind()) + } + + /// Iterable over the declared classical variables tracked by the circuit. + fn iter_declared_vars(&self, py: Python) -> PyResult> { + Ok(self.vars_by_type[DAGVarType::Declare as usize] + .bind(py) + .clone() + .into_any() + .iter()? + .unbind()) + } + + /// Iterable over all the classical variables tracked by the circuit. + fn iter_vars(&self, py: Python) -> PyResult> { + let out_set = PySet::empty_bound(py)?; + for var_type_set in &self.vars_by_type { + for var in var_type_set.bind(py).iter() { + out_set.add(var)?; + } + } + Ok(out_set.into_any().iter()?.unbind()) + } + + fn _has_edge(&self, source: usize, target: usize) -> bool { + self.dag + .contains_edge(NodeIndex::new(source), NodeIndex::new(target)) + } + + fn _is_dag(&self) -> bool { + rustworkx_core::petgraph::algo::toposort(&self.dag, None).is_ok() + } + + fn _in_edges(&self, py: Python, node_index: usize) -> Vec> { + self.dag + .edges_directed(NodeIndex::new(node_index), Incoming) + .map(|wire| { + ( + wire.source().index(), + wire.target().index(), + match wire.weight() { + Wire::Qubit(qubit) => self.qubits.get(*qubit).unwrap(), + Wire::Clbit(clbit) => self.clbits.get(*clbit).unwrap(), + Wire::Var(var) => var, + }, + ) + .into_py(py) + }) + .collect() + } + + fn _out_edges(&self, py: Python, node_index: usize) -> Vec> { + self.dag + .edges_directed(NodeIndex::new(node_index), Outgoing) + .map(|wire| { + ( + wire.source().index(), + wire.target().index(), + match wire.weight() { + Wire::Qubit(qubit) => self.qubits.get(*qubit).unwrap(), + Wire::Clbit(clbit) => self.clbits.get(*clbit).unwrap(), + Wire::Var(var) => var, + }, + ) + .into_py(py) + }) + .collect() + } + + fn _in_wires(&self, node_index: usize) -> Vec<&PyObject> { + self.dag + .edges_directed(NodeIndex::new(node_index), Incoming) + .map(|wire| match wire.weight() { + Wire::Qubit(qubit) => self.qubits.get(*qubit).unwrap(), + Wire::Clbit(clbit) => self.clbits.get(*clbit).unwrap(), + Wire::Var(var) => var, + }) + .collect() + } + + fn _out_wires(&self, node_index: usize) -> Vec<&PyObject> { + self.dag + .edges_directed(NodeIndex::new(node_index), Outgoing) + .map(|wire| match wire.weight() { + Wire::Qubit(qubit) => self.qubits.get(*qubit).unwrap(), + Wire::Clbit(clbit) => self.clbits.get(*clbit).unwrap(), + Wire::Var(var) => var, + }) + .collect() + } + + fn _find_successors_by_edge( + &self, + py: Python, + node_index: usize, + edge_checker: &Bound, + ) -> PyResult> { + let mut result = Vec::new(); + for e in self + .dag + .edges_directed(NodeIndex::new(node_index), Outgoing) + .unique_by(|e| e.id()) + { + let weight = match e.weight() { + Wire::Qubit(q) => self.qubits.get(*q).unwrap(), + Wire::Clbit(c) => self.clbits.get(*c).unwrap(), + Wire::Var(v) => v, + }; + if edge_checker.call1((weight,))?.extract::()? { + result.push(self.get_node(py, e.target())?); + } + } + Ok(result) + } + + fn _insert_1q_on_incoming_qubit( + &mut self, + py: Python, + node: &Bound, + old_index: usize, + ) -> PyResult<()> { + if let NodeType::Operation(inst) = self.pack_into(py, node)? { + self.increment_op(inst.op.name()); + let new_index = self.dag.add_node(NodeType::Operation(inst)); + let old_index: NodeIndex = NodeIndex::new(old_index); + let (parent_index, edge_index, weight) = self + .dag + .edges_directed(old_index, Incoming) + .map(|edge| (edge.source(), edge.id(), edge.weight().clone())) + .next() + .unwrap(); + self.dag.add_edge(parent_index, new_index, weight.clone()); + self.dag.add_edge(new_index, old_index, weight); + self.dag.remove_edge(edge_index); + Ok(()) + } else { + Err(PyTypeError::new_err("Invalid node type input")) + } + } + + fn _edges(&self, py: Python) -> Vec { + self.dag + .edge_indices() + .map(|index| { + let wire = self.dag.edge_weight(index).unwrap(); + match wire { + Wire::Qubit(qubit) => self.qubits.get(*qubit).to_object(py), + Wire::Clbit(clbit) => self.clbits.get(*clbit).to_object(py), + Wire::Var(var) => var.clone_ref(py), + } + }) + .collect() + } +} + +impl DAGCircuit { + /// Return an iterator of gate runs with non-conditional op nodes of given names + pub fn collect_runs( + &self, + namelist: HashSet, + ) -> Option> + '_> { + let filter_fn = move |node_index: NodeIndex| -> Result { + let node = &self.dag[node_index]; + match node { + NodeType::Operation(inst) => Ok(namelist.contains(inst.op.name()) + && match &inst.extra_attrs { + None => true, + Some(attrs) => attrs.condition.is_none(), + }), + _ => Ok(false), + } + }; + rustworkx_core::dag_algo::collect_runs(&self.dag, filter_fn) + .map(|node_iter| node_iter.map(|x| x.unwrap())) + } + + /// Return a set of non-conditional runs of 1q "op" nodes. + pub fn collect_1q_runs(&self) -> Option> + '_> { + let filter_fn = move |node_index: NodeIndex| -> Result { + let node = &self.dag[node_index]; + match node { + NodeType::Operation(inst) => Ok(inst.op.num_qubits() == 1 + && inst.op.num_clbits() == 0 + && !inst.is_parameterized() + && (inst.op.try_standard_gate().is_some() + || inst.op.matrix(inst.params_view()).is_some()) + && inst.condition().is_none()), + _ => Ok(false), + } + }; + rustworkx_core::dag_algo::collect_runs(&self.dag, filter_fn) + .map(|node_iter| node_iter.map(|x| x.unwrap())) + } + + /// Return a set of non-conditional runs of 2q "op" nodes. + pub fn collect_2q_runs(&self) -> Option>> { + let filter_fn = move |node_index: NodeIndex| -> Result, Infallible> { + let node = &self.dag[node_index]; + match node { + NodeType::Operation(inst) => match inst.op.view() { + OperationRef::Standard(gate) => Ok(Some( + gate.num_qubits() <= 2 + && inst.condition().is_none() + && !inst.is_parameterized(), + )), + OperationRef::Gate(gate) => Ok(Some( + gate.num_qubits() <= 2 + && inst.condition().is_none() + && !inst.is_parameterized(), + )), + _ => Ok(Some(false)), + }, + _ => Ok(None), + } + }; + + let color_fn = move |edge_index: EdgeIndex| -> Result, Infallible> { + let wire = self.dag.edge_weight(edge_index).unwrap(); + match wire { + Wire::Qubit(index) => Ok(Some(index.0 as usize)), + _ => Ok(None), + } + }; + rustworkx_core::dag_algo::collect_bicolor_runs(&self.dag, filter_fn, color_fn).unwrap() + } + + fn increment_op(&mut self, op: &str) { + match self.op_names.get_mut(op) { + Some(count) => { + *count += 1; + } + None => { + self.op_names.insert(op.to_string(), 1); + } + } + } + + fn decrement_op(&mut self, op: &str) { + match self.op_names.get_mut(op) { + Some(count) => { + if *count > 1 { + *count -= 1; + } else { + self.op_names.swap_remove(op); + } + } + None => panic!("Cannot decrement something not added!"), + } + } + + fn quantum_predecessors(&self, node: NodeIndex) -> impl Iterator + '_ { + self.dag + .edges_directed(node, Incoming) + .filter_map(|e| match e.weight() { + Wire::Qubit(_) => Some(e.source()), + _ => None, + }) + .unique() + } + + fn quantum_successors(&self, node: NodeIndex) -> impl Iterator + '_ { + self.dag + .edges_directed(node, Outgoing) + .filter_map(|e| match e.weight() { + Wire::Qubit(_) => Some(e.target()), + _ => None, + }) + .unique() + } + + /// Apply a [PackedInstruction] to the back of the circuit. + /// + /// The provided `instr` MUST be valid for this DAG, e.g. its + /// bits, registers, vars, and interner IDs must be valid in + /// this DAG. + /// + /// This is mostly used to apply operations from one DAG to + /// another that was created from the first via + /// [DAGCircuit::copy_empty_like]. + fn push_back(&mut self, py: Python, instr: PackedInstruction) -> PyResult { + let op_name = instr.op.name(); + let (all_cbits, vars): (Vec, Option>) = { + if self.may_have_additional_wires(py, &instr) { + let mut clbits: HashSet = + HashSet::from_iter(self.cargs_cache.intern(instr.clbits).iter().copied()); + let (additional_clbits, additional_vars) = + self.additional_wires(py, instr.op.view(), instr.condition())?; + for clbit in additional_clbits { + clbits.insert(clbit); + } + (clbits.into_iter().collect(), Some(additional_vars)) + } else { + (self.cargs_cache.intern(instr.clbits).to_vec(), None) + } + }; + + self.increment_op(op_name); + + let qubits_id = instr.qubits; + let new_node = self.dag.add_node(NodeType::Operation(instr)); + + // Put the new node in-between the previously "last" nodes on each wire + // and the output map. + let output_nodes: HashSet = self + .qargs_cache + .intern(qubits_id) + .iter() + .map(|q| self.qubit_io_map.get(q.0 as usize).map(|x| x[1]).unwrap()) + .chain( + all_cbits + .iter() + .map(|c| self.clbit_io_map.get(c.0 as usize).map(|x| x[1]).unwrap()), + ) + .chain( + vars.iter() + .flatten() + .map(|v| self.var_output_map.get(py, v).unwrap()), + ) + .collect(); + + for output_node in output_nodes { + let last_edges: Vec<_> = self + .dag + .edges_directed(output_node, Incoming) + .map(|e| (e.source(), e.id(), e.weight().clone())) + .collect(); + for (source, old_edge, weight) in last_edges.into_iter() { + self.dag.add_edge(source, new_node, weight.clone()); + self.dag.add_edge(new_node, output_node, weight); + self.dag.remove_edge(old_edge); + } + } + + Ok(new_node) + } + + /// Apply a [PackedInstruction] to the front of the circuit. + /// + /// The provided `instr` MUST be valid for this DAG, e.g. its + /// bits, registers, vars, and interner IDs must be valid in + /// this DAG. + /// + /// This is mostly used to apply operations from one DAG to + /// another that was created from the first via + /// [DAGCircuit::copy_empty_like]. + fn push_front(&mut self, py: Python, inst: PackedInstruction) -> PyResult { + let op_name = inst.op.name(); + let (all_cbits, vars): (Vec, Option>) = { + if self.may_have_additional_wires(py, &inst) { + let mut clbits: HashSet = + HashSet::from_iter(self.cargs_cache.intern(inst.clbits).iter().cloned()); + let (additional_clbits, additional_vars) = + self.additional_wires(py, inst.op.view(), inst.condition())?; + for clbit in additional_clbits { + clbits.insert(clbit); + } + (clbits.into_iter().collect(), Some(additional_vars)) + } else { + (self.cargs_cache.intern(inst.clbits).to_vec(), None) + } + }; + + self.increment_op(op_name); + + let qubits_id = inst.qubits; + let new_node = self.dag.add_node(NodeType::Operation(inst)); + + // Put the new node in-between the input map and the previously + // "first" nodes on each wire. + let mut input_nodes: Vec = self + .qargs_cache + .intern(qubits_id) + .iter() + .map(|q| self.qubit_io_map[q.0 as usize][0]) + .chain(all_cbits.iter().map(|c| self.clbit_io_map[c.0 as usize][0])) + .collect(); + if let Some(vars) = vars { + for var in vars { + input_nodes.push(self.var_input_map.get(py, &var).unwrap()); + } + } + + for input_node in input_nodes { + let first_edges: Vec<_> = self + .dag + .edges_directed(input_node, Outgoing) + .map(|e| (e.target(), e.id(), e.weight().clone())) + .collect(); + for (target, old_edge, weight) in first_edges.into_iter() { + self.dag.add_edge(input_node, new_node, weight.clone()); + self.dag.add_edge(new_node, target, weight); + self.dag.remove_edge(old_edge); + } + } + + Ok(new_node) + } + + fn sort_key(&self, node: NodeIndex) -> SortKeyType { + match &self.dag[node] { + NodeType::Operation(packed) => ( + self.qargs_cache.intern(packed.qubits).as_slice(), + self.cargs_cache.intern(packed.clbits).as_slice(), + ), + NodeType::QubitIn(q) => (std::slice::from_ref(q), &[Clbit(u32::MAX)]), + NodeType::QubitOut(_q) => (&[Qubit(u32::MAX)], &[Clbit(u32::MAX)]), + NodeType::ClbitIn(c) => (&[Qubit(u32::MAX)], std::slice::from_ref(c)), + NodeType::ClbitOut(_c) => (&[Qubit(u32::MAX)], &[Clbit(u32::MAX)]), + _ => (&[], &[]), + } + } + + fn topological_nodes(&self) -> PyResult> { + let key = |node: NodeIndex| -> Result { Ok(self.sort_key(node)) }; + let nodes = + rustworkx_core::dag_algo::lexicographical_topological_sort(&self.dag, key, false, None) + .map_err(|e| match e { + rustworkx_core::dag_algo::TopologicalSortError::CycleOrBadInitialState => { + PyValueError::new_err(format!("{}", e)) + } + rustworkx_core::dag_algo::TopologicalSortError::KeyError(_) => { + unreachable!() + } + })?; + Ok(nodes.into_iter()) + } + + fn topological_op_nodes(&self) -> PyResult + '_> { + Ok(self.topological_nodes()?.filter(|node: &NodeIndex| { + matches!(self.dag.node_weight(*node), Some(NodeType::Operation(_))) + })) + } + + fn topological_key_sort( + &self, + py: Python, + key: &Bound, + ) -> PyResult> { + // This path (user provided key func) is not ideal, since we no longer + // use a string key after moving to Rust, in favor of using a tuple + // of the qargs and cargs interner IDs of the node. + let key = |node: NodeIndex| -> PyResult { + let node = self.get_node(py, node)?; + key.call1((node,))?.extract() + }; + Ok( + rustworkx_core::dag_algo::lexicographical_topological_sort(&self.dag, key, false, None) + .map_err(|e| match e { + rustworkx_core::dag_algo::TopologicalSortError::CycleOrBadInitialState => { + PyValueError::new_err(format!("{}", e)) + } + rustworkx_core::dag_algo::TopologicalSortError::KeyError(ref e) => { + e.clone_ref(py) + } + })? + .into_iter(), + ) + } + + fn is_wire_idle(&self, py: Python, wire: &Wire) -> PyResult { + let (input_node, output_node) = match wire { + Wire::Qubit(qubit) => ( + self.qubit_io_map[qubit.0 as usize][0], + self.qubit_io_map[qubit.0 as usize][1], + ), + Wire::Clbit(clbit) => ( + self.clbit_io_map[clbit.0 as usize][0], + self.clbit_io_map[clbit.0 as usize][1], + ), + Wire::Var(var) => ( + self.var_input_map.get(py, var).unwrap(), + self.var_output_map.get(py, var).unwrap(), + ), + }; + + let child = self + .dag + .neighbors_directed(input_node, Outgoing) + .next() + .ok_or_else(|| { + DAGCircuitError::new_err(format!( + "Invalid dagcircuit input node {:?} has no output", + input_node + )) + })?; + + Ok(child == output_node) + } + + fn may_have_additional_wires(&self, py: Python, instr: &PackedInstruction) -> bool { + if instr.condition().is_some() { + return true; + } + let OperationRef::Instruction(inst) = instr.op.view() else { + return false; + }; + inst.control_flow() + || inst + .instruction + .bind(py) + .is_instance(imports::STORE_OP.get_bound(py)) + .unwrap() + } + + fn additional_wires( + &self, + py: Python, + op: OperationRef, + condition: Option<&PyObject>, + ) -> PyResult<(Vec, Vec)> { + let wires_from_expr = |node: &Bound| -> PyResult<(Vec, Vec)> { + let mut clbits = Vec::new(); + let mut vars = Vec::new(); + for var in imports::ITER_VARS.get_bound(py).call1((node,))?.iter()? { + let var = var?; + let var_var = var.getattr("var")?; + if var_var.is_instance(imports::CLBIT.get_bound(py))? { + clbits.push(self.clbits.find(&var_var).unwrap()); + } else if var_var.is_instance(imports::CLASSICAL_REGISTER.get_bound(py))? { + for bit in var_var.iter().unwrap() { + clbits.push(self.clbits.find(&bit?).unwrap()); + } + } else { + vars.push(var.unbind()); + } + } + Ok((clbits, vars)) + }; + + let mut clbits = Vec::new(); + let mut vars = Vec::new(); + if let Some(condition) = condition { + let condition = condition.bind(py); + if !condition.is_none() { + if condition.is_instance(imports::EXPR.get_bound(py)).unwrap() { + let (expr_clbits, expr_vars) = wires_from_expr(condition)?; + for bit in expr_clbits { + clbits.push(bit); + } + for var in expr_vars { + vars.push(var); + } + } else { + for bit in self + .control_flow_module + .condition_resources(condition)? + .clbits + .bind(py) + { + clbits.push(self.clbits.find(&bit).unwrap()); + } + } + } + } + + if let OperationRef::Instruction(inst) = op { + let op = inst.instruction.bind(py); + if inst.control_flow() { + for var in op.call_method0("iter_captured_vars")?.iter()? { + vars.push(var?.unbind()) + } + if op.is_instance(imports::SWITCH_CASE_OP.get_bound(py))? { + let target = op.getattr(intern!(py, "target"))?; + if target.is_instance(imports::CLBIT.get_bound(py))? { + clbits.push(self.clbits.find(&target).unwrap()); + } else if target.is_instance(imports::CLASSICAL_REGISTER.get_bound(py))? { + for bit in target.iter()? { + clbits.push(self.clbits.find(&bit?).unwrap()); + } + } else { + let (expr_clbits, expr_vars) = wires_from_expr(&target)?; + for bit in expr_clbits { + clbits.push(bit); + } + for var in expr_vars { + vars.push(var); + } + } + } + } else if op.is_instance(imports::STORE_OP.get_bound(py))? { + let (expr_clbits, expr_vars) = wires_from_expr(&op.getattr("lvalue")?)?; + for bit in expr_clbits { + clbits.push(bit); + } + for var in expr_vars { + vars.push(var); + } + let (expr_clbits, expr_vars) = wires_from_expr(&op.getattr("rvalue")?)?; + for bit in expr_clbits { + clbits.push(bit); + } + for var in expr_vars { + vars.push(var); + } + } + } + Ok((clbits, vars)) + } + + /// Add a qubit or bit to the circuit. + /// + /// Args: + /// wire: the wire to be added + /// + /// This adds a pair of in and out nodes connected by an edge. + /// + /// Raises: + /// DAGCircuitError: if trying to add duplicate wire + fn add_wire(&mut self, py: Python, wire: Wire) -> PyResult<()> { + let (in_node, out_node) = match wire { + Wire::Qubit(qubit) => { + if (qubit.0 as usize) >= self.qubit_io_map.len() { + let input_node = self.dag.add_node(NodeType::QubitIn(qubit)); + let output_node = self.dag.add_node(NodeType::QubitOut(qubit)); + self.qubit_io_map.push([input_node, output_node]); + Ok((input_node, output_node)) + } else { + Err(DAGCircuitError::new_err("qubit wire already exists!")) + } + } + Wire::Clbit(clbit) => { + if (clbit.0 as usize) >= self.clbit_io_map.len() { + let input_node = self.dag.add_node(NodeType::ClbitIn(clbit)); + let output_node = self.dag.add_node(NodeType::ClbitOut(clbit)); + self.clbit_io_map.push([input_node, output_node]); + Ok((input_node, output_node)) + } else { + Err(DAGCircuitError::new_err("classical wire already exists!")) + } + } + Wire::Var(ref var) => { + if self.var_input_map.contains_key(py, var) + || self.var_output_map.contains_key(py, var) + { + return Err(DAGCircuitError::new_err("var wire already exists!")); + } + let in_node = self.dag.add_node(NodeType::VarIn(var.clone_ref(py))); + let out_node = self.dag.add_node(NodeType::VarOut(var.clone_ref(py))); + self.var_input_map.insert(py, var.clone_ref(py), in_node); + self.var_output_map.insert(py, var.clone_ref(py), out_node); + Ok((in_node, out_node)) + } + }?; + + self.dag.add_edge(in_node, out_node, wire); + Ok(()) + } + + /// Get the nodes on the given wire. + /// + /// Note: result is empty if the wire is not in the DAG. + fn nodes_on_wire(&self, py: Python, wire: &Wire, only_ops: bool) -> Vec { + let mut nodes = Vec::new(); + let mut current_node = match wire { + Wire::Qubit(qubit) => self.qubit_io_map.get(qubit.0 as usize).map(|x| x[0]), + Wire::Clbit(clbit) => self.clbit_io_map.get(clbit.0 as usize).map(|x| x[0]), + Wire::Var(var) => self.var_input_map.get(py, var), + }; + + while let Some(node) = current_node { + if only_ops { + let node_weight = self.dag.node_weight(node).unwrap(); + if let NodeType::Operation(_) = node_weight { + nodes.push(node); + } + } else { + nodes.push(node); + } + + let edges = self.dag.edges_directed(node, Outgoing); + current_node = edges.into_iter().find_map(|edge| { + if edge.weight() == wire { + Some(edge.target()) + } else { + None + } + }); + } + nodes + } + + fn remove_idle_wire(&mut self, py: Python, wire: Wire) -> PyResult<()> { + let [in_node, out_node] = match wire { + Wire::Qubit(qubit) => self.qubit_io_map[qubit.0 as usize], + Wire::Clbit(clbit) => self.clbit_io_map[clbit.0 as usize], + Wire::Var(var) => [ + self.var_input_map.remove(py, &var).unwrap(), + self.var_output_map.remove(py, &var).unwrap(), + ], + }; + self.dag.remove_node(in_node); + self.dag.remove_node(out_node); + Ok(()) + } + + fn add_qubit_unchecked(&mut self, py: Python, bit: &Bound) -> PyResult { + let qubit = self.qubits.add(py, bit, false)?; + self.qubit_locations.bind(py).set_item( + bit, + Py::new( + py, + BitLocations { + index: (self.qubits.len() - 1), + registers: PyList::empty_bound(py).unbind(), + }, + )?, + )?; + self.add_wire(py, Wire::Qubit(qubit))?; + Ok(qubit) + } + + fn add_clbit_unchecked(&mut self, py: Python, bit: &Bound) -> PyResult { + let clbit = self.clbits.add(py, bit, false)?; + self.clbit_locations.bind(py).set_item( + bit, + Py::new( + py, + BitLocations { + index: (self.clbits.len() - 1), + registers: PyList::empty_bound(py).unbind(), + }, + )?, + )?; + self.add_wire(py, Wire::Clbit(clbit))?; + Ok(clbit) + } + + pub fn get_node(&self, py: Python, node: NodeIndex) -> PyResult> { + self.unpack_into(py, node, self.dag.node_weight(node).unwrap()) + } + + /// Remove an operation node n. + /// + /// Add edges from predecessors to successors. + fn remove_op_node(&mut self, index: NodeIndex) { + let mut edge_list: Vec<(NodeIndex, NodeIndex, Wire)> = Vec::new(); + for (source, in_weight) in self + .dag + .edges_directed(index, Incoming) + .map(|x| (x.source(), x.weight())) + { + for (target, out_weight) in self + .dag + .edges_directed(index, Outgoing) + .map(|x| (x.target(), x.weight())) + { + if in_weight == out_weight { + edge_list.push((source, target, in_weight.clone())); + } + } + } + for (source, target, weight) in edge_list { + self.dag.add_edge(source, target, weight); + } + + match self.dag.remove_node(index) { + Some(NodeType::Operation(packed)) => { + let op_name = packed.op.name(); + self.decrement_op(op_name); + } + _ => panic!("Must be called with valid operation node!"), + } + } + + /// Returns an iterator of the ancestors indices of a node. + pub fn ancestors(&self, node: NodeIndex) -> impl Iterator + '_ { + core_ancestors(&self.dag, node).filter(move |next| next != &node) + } + + /// Returns an iterator of the descendants of a node as DAGOpNodes and DAGOutNodes. + pub fn descendants(&self, node: NodeIndex) -> impl Iterator + '_ { + core_descendants(&self.dag, node).filter(move |next| next != &node) + } + + /// Returns an iterator of tuples of (DAGNode, [DAGNodes]) where the DAGNode is the current node + /// and [DAGNode] is its successors in BFS order. + pub fn bfs_successors( + &self, + node: NodeIndex, + ) -> impl Iterator)> + '_ { + core_bfs_successors(&self.dag, node).filter(move |(_, others)| !others.is_empty()) + } + + fn pack_into(&mut self, py: Python, b: &Bound) -> Result { + Ok(if let Ok(in_node) = b.downcast::() { + let in_node = in_node.borrow(); + let wire = in_node.wire.bind(py); + if wire.is_instance(imports::QUBIT.get_bound(py))? { + NodeType::QubitIn(self.qubits.find(wire).unwrap()) + } else if wire.is_instance(imports::CLBIT.get_bound(py))? { + NodeType::ClbitIn(self.clbits.find(wire).unwrap()) + } else { + NodeType::VarIn(wire.clone().unbind()) + } + } else if let Ok(out_node) = b.downcast::() { + let out_node = out_node.borrow(); + let wire = out_node.wire.bind(py); + if wire.is_instance(imports::QUBIT.get_bound(py))? { + NodeType::QubitOut(self.qubits.find(wire).unwrap()) + } else if wire.is_instance(imports::CLBIT.get_bound(py))? { + NodeType::ClbitOut(self.clbits.find(wire).unwrap()) + } else { + NodeType::VarIn(wire.clone().unbind()) + } + } else if let Ok(op_node) = b.downcast::() { + let op_node = op_node.borrow(); + let qubits = Interner::intern( + &mut self.qargs_cache, + self.qubits + .map_bits(op_node.instruction.qubits.bind(py))? + .collect(), + )?; + let clbits = Interner::intern( + &mut self.cargs_cache, + self.clbits + .map_bits(op_node.instruction.clbits.bind(py))? + .collect(), + )?; + let params = (!op_node.instruction.params.is_empty()) + .then(|| Box::new(op_node.instruction.params.clone())); + let inst = PackedInstruction { + op: op_node.instruction.operation.clone(), + qubits, + clbits, + params, + extra_attrs: op_node.instruction.extra_attrs.clone(), + #[cfg(feature = "cache_pygates")] + py_op: op_node.instruction.py_op.clone(), + }; + NodeType::Operation(inst) + } else { + return Err(PyTypeError::new_err("Invalid type for DAGNode")); + }) + } + + fn unpack_into(&self, py: Python, id: NodeIndex, weight: &NodeType) -> PyResult> { + let dag_node = match weight { + NodeType::QubitIn(qubit) => Py::new( + py, + DAGInNode::new(py, id, self.qubits.get(*qubit).unwrap().clone_ref(py)), + )? + .into_any(), + NodeType::QubitOut(qubit) => Py::new( + py, + DAGOutNode::new(py, id, self.qubits.get(*qubit).unwrap().clone_ref(py)), + )? + .into_any(), + NodeType::ClbitIn(clbit) => Py::new( + py, + DAGInNode::new(py, id, self.clbits.get(*clbit).unwrap().clone_ref(py)), + )? + .into_any(), + NodeType::ClbitOut(clbit) => Py::new( + py, + DAGOutNode::new(py, id, self.clbits.get(*clbit).unwrap().clone_ref(py)), + )? + .into_any(), + NodeType::Operation(packed) => { + let qubits = self.qargs_cache.intern(packed.qubits); + let clbits = self.cargs_cache.intern(packed.clbits); + Py::new( + py, + ( + DAGOpNode { + instruction: CircuitInstruction { + operation: packed.op.clone(), + qubits: PyTuple::new_bound(py, self.qubits.map_indices(qubits)) + .unbind(), + clbits: PyTuple::new_bound(py, self.clbits.map_indices(clbits)) + .unbind(), + params: packed.params_view().iter().cloned().collect(), + extra_attrs: packed.extra_attrs.clone(), + #[cfg(feature = "cache_pygates")] + py_op: packed.py_op.clone(), + }, + sort_key: format!("{:?}", self.sort_key(id)).into_py(py), + }, + DAGNode { node: Some(id) }, + ), + )? + .into_any() + } + NodeType::VarIn(var) => { + Py::new(py, DAGInNode::new(py, id, var.clone_ref(py)))?.into_any() + } + NodeType::VarOut(var) => { + Py::new(py, DAGOutNode::new(py, id, var.clone_ref(py)))?.into_any() + } + }; + Ok(dag_node) + } + + /// Returns an iterator over all the indices that refer to an `Operation` node in the `DAGCircuit.` + pub fn op_nodes<'a>( + &'a self, + include_directives: bool, + ) -> Box + 'a> { + let node_ops_iter = self + .dag + .node_references() + .filter_map(|(node_index, node_type)| match node_type { + NodeType::Operation(ref node) => Some((node_index, node)), + _ => None, + }); + if !include_directives { + Box::new(node_ops_iter.filter_map(|(index, node)| { + if !node.op.directive() { + Some(index) + } else { + None + } + })) + } else { + Box::new(node_ops_iter.map(|(index, _)| index)) + } + } + + pub fn op_nodes_by_py_type<'a>( + &'a self, + op: &'a Bound, + include_directives: bool, + ) -> impl Iterator + 'a { + self.dag + .node_references() + .filter_map(move |(node, weight)| { + if let NodeType::Operation(ref packed) = weight { + if !include_directives && packed.op.directive() { + None + } else if packed.op.py_op_is_instance(op).unwrap() { + Some(node) + } else { + None + } + } else { + None + } + }) + } + + /// Returns an iterator over a list layers of the `DAGCircuit``. + pub fn multigraph_layers(&self, py: Python) -> impl Iterator> + '_ { + let mut first_layer: Vec<_> = self.qubit_io_map.iter().map(|x| x[0]).collect(); + first_layer.extend(self.clbit_io_map.iter().map(|x| x[0])); + first_layer.extend(self.var_input_map.values(py)); + // A DAG is by definition acyclical, therefore unwrapping the layer should never fail. + layers(&self.dag, first_layer).map(|layer| match layer { + Ok(layer) => layer, + Err(_) => unreachable!("Not a DAG."), + }) + } + + /// Returns an iterator over the first layer of the `DAGCircuit``. + pub fn front_layer<'a>(&'a self, py: Python) -> Box + 'a> { + let mut graph_layers = self.multigraph_layers(py); + graph_layers.next(); + + let next_layer = graph_layers.next(); + match next_layer { + Some(layer) => Box::new(layer.into_iter().filter(|node| { + matches!(self.dag.node_weight(*node).unwrap(), NodeType::Operation(_)) + })), + None => Box::new(vec![].into_iter()), + } + } + + fn substitute_node_with_subgraph( + &mut self, + py: Python, + node: NodeIndex, + other: &DAGCircuit, + qubit_map: &HashMap, + clbit_map: &HashMap, + var_map: &Py, + ) -> PyResult> { + if self.dag.node_weight(node).is_none() { + return Err(PyIndexError::new_err(format!( + "Specified node {} is not in this graph", + node.index() + ))); + } + + // Add wire from pred to succ if no ops on mapped wire on ``other`` + for (in_dag_wire, self_wire) in qubit_map.iter() { + let [input_node, out_node] = other.qubit_io_map[in_dag_wire.0 as usize]; + if other.dag.find_edge(input_node, out_node).is_some() { + let pred = self + .dag + .edges_directed(node, Incoming) + .find(|edge| { + if let Wire::Qubit(bit) = edge.weight() { + bit == self_wire + } else { + false + } + }) + .unwrap(); + let succ = self + .dag + .edges_directed(node, Outgoing) + .find(|edge| { + if let Wire::Qubit(bit) = edge.weight() { + bit == self_wire + } else { + false + } + }) + .unwrap(); + self.dag + .add_edge(pred.source(), succ.target(), Wire::Qubit(*self_wire)); + } + } + for (in_dag_wire, self_wire) in clbit_map.iter() { + let [input_node, out_node] = other.clbit_io_map[in_dag_wire.0 as usize]; + if other.dag.find_edge(input_node, out_node).is_some() { + let pred = self + .dag + .edges_directed(node, Incoming) + .find(|edge| { + if let Wire::Clbit(bit) = edge.weight() { + bit == self_wire + } else { + false + } + }) + .unwrap(); + let succ = self + .dag + .edges_directed(node, Outgoing) + .find(|edge| { + if let Wire::Clbit(bit) = edge.weight() { + bit == self_wire + } else { + false + } + }) + .unwrap(); + self.dag + .add_edge(pred.source(), succ.target(), Wire::Clbit(*self_wire)); + } + } + + let bound_var_map = var_map.bind(py); + let node_filter = |node: NodeIndex| -> bool { + match other.dag[node] { + NodeType::Operation(_) => !other + .dag + .edges_directed(node, petgraph::Direction::Outgoing) + .any(|edge| match edge.weight() { + Wire::Qubit(qubit) => !qubit_map.contains_key(qubit), + Wire::Clbit(clbit) => !clbit_map.contains_key(clbit), + Wire::Var(var) => !bound_var_map.contains(var).unwrap(), + }), + _ => false, + } + }; + let reverse_qubit_map: HashMap = + qubit_map.iter().map(|(x, y)| (*y, *x)).collect(); + let reverse_clbit_map: HashMap = + clbit_map.iter().map(|(x, y)| (*y, *x)).collect(); + let reverse_var_map = PyDict::new_bound(py); + for (k, v) in bound_var_map.iter() { + reverse_var_map.set_item(v, k)?; + } + // Copy nodes from other to self + let mut out_map: IndexMap = + IndexMap::with_capacity_and_hasher(other.dag.node_count(), RandomState::default()); + for old_index in other.dag.node_indices() { + if !node_filter(old_index) { + continue; + } + let mut new_node = other.dag[old_index].clone(); + if let NodeType::Operation(ref mut new_inst) = new_node { + let new_qubit_indices: Vec = other + .qargs_cache + .intern(new_inst.qubits) + .iter() + .map(|old_qubit| qubit_map[old_qubit]) + .collect(); + let new_clbit_indices: Vec = other + .cargs_cache + .intern(new_inst.clbits) + .iter() + .map(|old_clbit| clbit_map[old_clbit]) + .collect(); + new_inst.qubits = Interner::intern(&mut self.qargs_cache, new_qubit_indices)?; + new_inst.clbits = Interner::intern(&mut self.cargs_cache, new_clbit_indices)?; + self.increment_op(new_inst.op.name()); + } + let new_index = self.dag.add_node(new_node); + out_map.insert(old_index, new_index); + } + // If no nodes are copied bail here since there is nothing left + // to do. + if out_map.is_empty() { + match self.dag.remove_node(node) { + Some(NodeType::Operation(packed)) => { + let op_name = packed.op.name(); + self.decrement_op(op_name); + } + _ => unreachable!("Must be called with valid operation node!"), + } + // Return a new empty map to clear allocation from out_map + return Ok(IndexMap::default()); + } + // Copy edges from other to self + for edge in other.dag.edge_references().filter(|edge| { + out_map.contains_key(&edge.target()) && out_map.contains_key(&edge.source()) + }) { + self.dag.add_edge( + out_map[&edge.source()], + out_map[&edge.target()], + match edge.weight() { + Wire::Qubit(qubit) => Wire::Qubit(qubit_map[qubit]), + Wire::Clbit(clbit) => Wire::Clbit(clbit_map[clbit]), + Wire::Var(var) => Wire::Var(bound_var_map.get_item(var)?.unwrap().unbind()), + }, + ); + } + // Add edges to/from node to nodes in other + let edges: Vec<(NodeIndex, NodeIndex, Wire)> = self + .dag + .edges_directed(node, Incoming) + .map(|x| (x.source(), x.target(), x.weight().clone())) + .collect(); + for (source, _target, weight) in edges { + let wire_input_id = match weight { + Wire::Qubit(qubit) => other + .qubit_io_map + .get(reverse_qubit_map[&qubit].0 as usize) + .map(|x| x[0]), + Wire::Clbit(clbit) => other + .clbit_io_map + .get(reverse_clbit_map[&clbit].0 as usize) + .map(|x| x[0]), + Wire::Var(ref var) => { + let index = &reverse_var_map.get_item(var)?.unwrap().unbind(); + other.var_input_map.get(py, index) + } + }; + let old_index = + wire_input_id.and_then(|x| other.dag.neighbors_directed(x, Outgoing).next()); + let target_out = match old_index { + Some(old_index) => match out_map.get(&old_index) { + Some(new_index) => *new_index, + None => { + // If the index isn't in the node map we've already added the edges as + // part of the idle wire handling at the top of this method so just + // move on. + continue; + } + }, + None => continue, + }; + self.dag.add_edge(source, target_out, weight); + } + let edges: Vec<(NodeIndex, NodeIndex, Wire)> = self + .dag + .edges_directed(node, Outgoing) + .map(|x| (x.source(), x.target(), x.weight().clone())) + .collect(); + for (_source, target, weight) in edges { + let wire_output_id = match weight { + Wire::Qubit(qubit) => other + .qubit_io_map + .get(reverse_qubit_map[&qubit].0 as usize) + .map(|x| x[1]), + Wire::Clbit(clbit) => other + .clbit_io_map + .get(reverse_clbit_map[&clbit].0 as usize) + .map(|x| x[1]), + Wire::Var(ref var) => { + let index = &reverse_var_map.get_item(var)?.unwrap().unbind(); + other.var_output_map.get(py, index) + } + }; + let old_index = + wire_output_id.and_then(|x| other.dag.neighbors_directed(x, Incoming).next()); + let source_out = match old_index { + Some(old_index) => match out_map.get(&old_index) { + Some(new_index) => *new_index, + None => { + // If the index isn't in the node map we've already added the edges as + // part of the idle wire handling at the top of this method so just + // move on. + continue; + } + }, + None => continue, + }; + self.dag.add_edge(source_out, target, weight); + } + // Remove node + if let NodeType::Operation(inst) = &self.dag[node] { + self.decrement_op(inst.op.name().to_string().as_str()); + } + self.dag.remove_node(node); + Ok(out_map) + } + + fn add_var(&mut self, py: Python, var: &Bound, type_: DAGVarType) -> PyResult<()> { + // The setup of the initial graph structure between an "in" and an "out" node is the same as + // the bit-related `_add_wire`, but this logically needs to do different bookkeeping around + // tracking the properties + if !var.getattr("standalone")?.extract::()? { + return Err(DAGCircuitError::new_err( + "cannot add variables that wrap `Clbit` or `ClassicalRegister` instances", + )); + } + let var_name: String = var.getattr("name")?.extract::()?; + if let Some(previous) = self.vars_info.get(&var_name) { + if var.eq(previous.var.clone_ref(py))? { + return Err(DAGCircuitError::new_err("already present in the circuit")); + } + return Err(DAGCircuitError::new_err( + "cannot add var as its name shadows an existing var", + )); + } + let in_node = NodeType::VarIn(var.clone().unbind()); + let out_node = NodeType::VarOut(var.clone().unbind()); + let in_index = self.dag.add_node(in_node); + let out_index = self.dag.add_node(out_node); + self.dag + .add_edge(in_index, out_index, Wire::Var(var.clone().unbind())); + self.var_input_map + .insert(py, var.clone().unbind(), in_index); + self.var_output_map + .insert(py, var.clone().unbind(), out_index); + self.vars_by_type[type_ as usize] + .bind(py) + .add(var.clone().unbind())?; + self.vars_info.insert( + var_name, + DAGVarInfo { + var: var.clone().unbind(), + type_, + in_node: in_index, + out_node: out_index, + }, + ); + Ok(()) + } + + fn check_op_addition(&self, py: Python, inst: &PackedInstruction) -> PyResult<()> { + if let Some(condition) = inst.condition() { + self._check_condition(py, inst.op.name(), condition.bind(py))?; + } + + for b in self.qargs_cache.intern(inst.qubits) { + if self.qubit_io_map.len() - 1 < b.0 as usize { + return Err(DAGCircuitError::new_err(format!( + "qubit {} not found in output map", + self.qubits.get(*b).unwrap() + ))); + } + } + + for b in self.cargs_cache.intern(inst.clbits) { + if !self.clbit_io_map.len() - 1 < b.0 as usize { + return Err(DAGCircuitError::new_err(format!( + "clbit {} not found in output map", + self.clbits.get(*b).unwrap() + ))); + } + } + + if self.may_have_additional_wires(py, inst) { + let (clbits, vars) = self.additional_wires(py, inst.op.view(), inst.condition())?; + for b in clbits { + if !self.clbit_io_map.len() - 1 < b.0 as usize { + return Err(DAGCircuitError::new_err(format!( + "clbit {} not found in output map", + self.clbits.get(b).unwrap() + ))); + } + } + for v in vars { + if !self.var_output_map.contains_key(py, &v) { + return Err(DAGCircuitError::new_err(format!( + "var {} not found in output map", + v + ))); + } + } + } + Ok(()) + } +} + +/// Add to global phase. Global phase can only be Float or ParameterExpression so this +/// does not handle the full possibility of parameter values. +fn add_global_phase(py: Python, phase: &Param, other: &Param) -> PyResult { + Ok(match [phase, other] { + [Param::Float(a), Param::Float(b)] => Param::Float(a + b), + [Param::Float(a), Param::ParameterExpression(b)] => Param::ParameterExpression( + b.clone_ref(py) + .call_method1(py, intern!(py, "__radd__"), (*a,))?, + ), + [Param::ParameterExpression(a), Param::Float(b)] => Param::ParameterExpression( + a.clone_ref(py) + .call_method1(py, intern!(py, "__add__"), (*b,))?, + ), + [Param::ParameterExpression(a), Param::ParameterExpression(b)] => { + Param::ParameterExpression(a.clone_ref(py).call_method1( + py, + intern!(py, "__add__"), + (b,), + )?) + } + _ => panic!("Invalid global phase"), + }) +} + +type SortKeyType<'a> = (&'a [Qubit], &'a [Clbit]); diff --git a/crates/circuit/src/dag_node.rs b/crates/circuit/src/dag_node.rs index 9af82b74fa5a..ccae7a8c5d82 100644 --- a/crates/circuit/src/dag_node.rs +++ b/crates/circuit/src/dag_node.rs @@ -12,47 +12,89 @@ #[cfg(feature = "cache_pygates")] use std::cell::OnceCell; +use std::hash::Hasher; use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; use crate::imports::QUANTUM_CIRCUIT; -use crate::operations::Operation; +use crate::operations::{Operation, Param}; +use crate::TupleLikeArg; -use numpy::IntoPyArray; +use ahash::AHasher; +use approx::relative_eq; +use rustworkx_core::petgraph::stable_graph::NodeIndex; +use numpy::IntoPyArray; +use pyo3::exceptions::PyValueError; use pyo3::prelude::*; -use pyo3::types::{PyDict, PyList, PySequence, PyString, PyTuple}; +use pyo3::types::{PyString, PyTuple}; use pyo3::{intern, IntoPy, PyObject, PyResult, ToPyObject}; /// Parent class for DAGOpNode, DAGInNode, and DAGOutNode. #[pyclass(module = "qiskit._accelerate.circuit", subclass)] #[derive(Clone, Debug)] pub struct DAGNode { - #[pyo3(get, set)] - pub _node_id: isize, + pub node: Option, +} + +impl DAGNode { + #[inline] + pub fn py_nid(&self) -> isize { + self.node + .map(|node| node.index().try_into().unwrap()) + .unwrap_or(-1) + } } #[pymethods] impl DAGNode { #[new] #[pyo3(signature=(nid=-1))] - fn new(nid: isize) -> Self { - DAGNode { _node_id: nid } + fn py_new(nid: isize) -> PyResult { + Ok(DAGNode { + node: match nid { + -1 => None, + nid => { + let index: usize = match nid.try_into() { + Ok(index) => index, + Err(_) => { + return Err(PyValueError::new_err( + "Invalid node index, must be -1 or a non-negative integer", + )) + } + }; + Some(NodeIndex::new(index)) + } + }, + }) } - fn __getstate__(&self) -> isize { - self._node_id + #[getter(_node_id)] + fn get_py_node_id(&self) -> isize { + self.py_nid() } - fn __setstate__(&mut self, nid: isize) { - self._node_id = nid; + #[setter(_node_id)] + fn set_py_node_id(&mut self, nid: isize) { + self.node = match nid { + -1 => None, + nid => Some(NodeIndex::new(nid.try_into().unwrap())), + } + } + + fn __getstate__(&self) -> Option { + self.node.map(|node| node.index()) + } + + fn __setstate__(&mut self, index: Option) { + self.node = index.map(NodeIndex::new); } fn __lt__(&self, other: &DAGNode) -> bool { - self._node_id < other._node_id + self.py_nid() < other.py_nid() } fn __gt__(&self, other: &DAGNode) -> bool { - self._node_id > other._node_id + self.py_nid() > other.py_nid() } fn __str__(_self: &Bound) -> String { @@ -60,7 +102,7 @@ impl DAGNode { } fn __hash__(&self, py: Python) -> PyResult { - self._node_id.into_py(py).bind(py).hash() + self.py_nid().into_py(py).bind(py).hash() } } @@ -76,96 +118,124 @@ pub struct DAGOpNode { impl DAGOpNode { #[new] #[pyo3(signature = (op, qargs=None, cargs=None, *, dag=None))] - fn new( + pub fn py_new( py: Python, - op: &Bound, - qargs: Option<&Bound>, - cargs: Option<&Bound>, - dag: Option<&Bound>, - ) -> PyResult<(Self, DAGNode)> { - let qargs = - qargs.map_or_else(|| Ok(PyTuple::empty_bound(py)), PySequenceMethods::to_tuple)?; - let cargs = - cargs.map_or_else(|| Ok(PyTuple::empty_bound(py)), PySequenceMethods::to_tuple)?; - - let sort_key = match dag { - Some(dag) => { - let cache = dag - .getattr(intern!(py, "_key_cache"))? - .downcast_into_exact::()?; - let cache_key = PyTuple::new_bound(py, [&qargs, &cargs]); - match cache.get_item(&cache_key)? { - Some(key) => key, - None => { - let indices: PyResult> = qargs - .iter() - .chain(cargs.iter()) - .map(|bit| { - dag.call_method1(intern!(py, "find_bit"), (bit,))? - .getattr(intern!(py, "index")) - }) - .collect(); - let index_strs: Vec<_> = - indices?.into_iter().map(|i| format!("{:04}", i)).collect(); - let key = PyString::new_bound(py, index_strs.join(",").as_str()); - cache.set_item(&cache_key, &key)?; - key.into_any() + op: Bound, + qargs: Option, + cargs: Option, + #[allow(unused_variables)] dag: Option>, + ) -> PyResult> { + let py_op = op.extract::()?; + let qargs = qargs.map_or_else(|| PyTuple::empty_bound(py), |q| q.value); + let sort_key = qargs.str().unwrap().into(); + let cargs = cargs.map_or_else(|| PyTuple::empty_bound(py), |c| c.value); + let instruction = CircuitInstruction { + operation: py_op.operation, + qubits: qargs.unbind(), + clbits: cargs.unbind(), + params: py_op.params, + extra_attrs: py_op.extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op: op.unbind().into(), + }; + + Py::new( + py, + ( + DAGOpNode { + instruction, + sort_key, + }, + DAGNode { node: None }, + ), + ) + } + + fn __hash__(slf: PyRef<'_, Self>) -> PyResult { + let super_ = slf.as_ref(); + let mut hasher = AHasher::default(); + hasher.write_isize(super_.py_nid()); + hasher.write(slf.instruction.operation.name().as_bytes()); + Ok(hasher.finish()) + } + + fn __eq__(slf: PyRef, py: Python, other: &Bound) -> PyResult { + // This check is more restrictive by design as it's intended to replace + // object identitity for set/dict membership and not be a semantic equivalence + // check. We have an implementation of that as part of `DAGCircuit.__eq__` and + // this method is specifically to ensure nodes are the same. This means things + // like parameter equality are stricter to reject things like + // Param::Float(0.1) == Param::ParameterExpression(0.1) (if the expression was + // a python parameter equivalent to a bound value). + let Ok(other) = other.downcast::() else { + return Ok(false); + }; + let borrowed_other = other.borrow(); + let other_super = borrowed_other.as_ref(); + let super_ = slf.as_ref(); + + if super_.py_nid() != other_super.py_nid() { + return Ok(false); + } + if !slf + .instruction + .operation + .py_eq(py, &borrowed_other.instruction.operation)? + { + return Ok(false); + } + let params_eq = if slf.instruction.operation.try_standard_gate().is_some() { + let mut params_eq = true; + for (a, b) in slf + .instruction + .params + .iter() + .zip(borrowed_other.instruction.params.iter()) + { + let res = match [a, b] { + [Param::Float(float_a), Param::Float(float_b)] => { + relative_eq!(float_a, float_b, max_relative = 1e-10) + } + [Param::ParameterExpression(param_a), Param::ParameterExpression(param_b)] => { + param_a.bind(py).eq(param_b)? } + [Param::Obj(param_a), Param::Obj(param_b)] => param_a.bind(py).eq(param_b)?, + _ => false, + }; + if !res { + params_eq = false; + break; } } - None => qargs.str()?.into_any(), + params_eq + } else { + // We've already evaluated the parameters are equal here via the Python space equality + // check so if we're not comparing standard gates and we've reached this point we know + // the parameters are already equal. + true }; - Ok(( - DAGOpNode { - instruction: CircuitInstruction::py_new( - op, - Some(qargs.into_any()), - Some(cargs.into_any()), - )?, - sort_key: sort_key.unbind(), - }, - DAGNode { _node_id: -1 }, - )) + + Ok(params_eq + && slf + .instruction + .qubits + .bind(py) + .eq(borrowed_other.instruction.qubits.clone_ref(py))? + && slf + .instruction + .clbits + .bind(py) + .eq(borrowed_other.instruction.clbits.clone_ref(py))?) } - #[pyo3(signature = (instruction, /, *, dag=None, deepcopy=false))] + #[pyo3(signature = (instruction, /, *, deepcopy=false))] #[staticmethod] fn from_instruction( py: Python, mut instruction: CircuitInstruction, - dag: Option<&Bound>, deepcopy: bool, ) -> PyResult { - let qargs = instruction.qubits.bind(py); - let cargs = instruction.clbits.bind(py); - - let sort_key = match dag { - Some(dag) => { - let cache = dag - .getattr(intern!(py, "_key_cache"))? - .downcast_into_exact::()?; - let cache_key = PyTuple::new_bound(py, [&qargs, &cargs]); - match cache.get_item(&cache_key)? { - Some(key) => key, - None => { - let indices: PyResult> = qargs - .iter() - .chain(cargs.iter()) - .map(|bit| { - dag.call_method1(intern!(py, "find_bit"), (bit,))? - .getattr(intern!(py, "index")) - }) - .collect(); - let index_strs: Vec<_> = - indices?.into_iter().map(|i| format!("{:04}", i)).collect(); - let key = PyString::new_bound(py, index_strs.join(",").as_str()); - cache.set_item(&cache_key, &key)?; - key.into_any() - } - } - } - None => qargs.str()?.into_any(), - }; + let sort_key = instruction.qubits.bind(py).str().unwrap().into(); if deepcopy { instruction.operation = instruction.operation.py_deepcopy(py, None)?; #[cfg(feature = "cache_pygates")] @@ -173,17 +243,16 @@ impl DAGOpNode { instruction.py_op = OnceCell::new(); } } - let base = PyClassInitializer::from(DAGNode { _node_id: -1 }); + let base = PyClassInitializer::from(DAGNode { node: None }); let sub = base.add_subclass(DAGOpNode { instruction, - sort_key: sort_key.unbind(), + sort_key, }); Ok(Py::new(py, sub)?.to_object(py)) } - fn __reduce__(slf: PyRef) -> PyResult { - let py = slf.py(); - let state = (slf.as_ref()._node_id, &slf.sort_key); + fn __reduce__(slf: PyRef, py: Python) -> PyResult { + let state = (slf.as_ref().node.map(|node| node.index()), &slf.sort_key); Ok(( py.get_type_bound::(), ( @@ -197,8 +266,8 @@ impl DAGOpNode { } fn __setstate__(mut slf: PyRefMut, state: &Bound) -> PyResult<()> { - let (nid, sort_key): (isize, PyObject) = state.extract()?; - slf.as_mut()._node_id = nid; + let (index, sort_key): (Option, PyObject) = state.extract()?; + slf.as_mut().node = index.map(NodeIndex::new); slf.sort_key = sort_key; Ok(()) } @@ -247,16 +316,16 @@ impl DAGOpNode { #[getter] fn num_qubits(&self) -> u32 { - self.instruction.op().num_qubits() + self.instruction.operation.num_qubits() } #[getter] fn num_clbits(&self) -> u32 { - self.instruction.op().num_clbits() + self.instruction.operation.num_clbits() } #[getter] - fn get_qargs(&self, py: Python) -> Py { + pub fn get_qargs(&self, py: Python) -> Py { self.instruction.qubits.clone_ref(py) } @@ -266,7 +335,7 @@ impl DAGOpNode { } #[getter] - fn get_cargs(&self, py: Python) -> Py { + pub fn get_cargs(&self, py: Python) -> Py { self.instruction.clbits.clone_ref(py) } @@ -278,7 +347,7 @@ impl DAGOpNode { /// Returns the Instruction name corresponding to the op for this node #[getter] fn get_name(&self, py: Python) -> Py { - self.instruction.op().name().into_py(py) + self.instruction.operation.name().into_py(py) } #[getter] @@ -293,7 +362,7 @@ impl DAGOpNode { #[getter] fn matrix(&self, py: Python) -> Option { - let matrix = self.instruction.op().matrix(&self.instruction.params); + let matrix = self.instruction.operation.matrix(&self.instruction.params); matrix.map(|mat| mat.into_pyarray_bound(py).into()) } @@ -386,7 +455,7 @@ impl DAGOpNode { #[getter] fn definition<'py>(&self, py: Python<'py>) -> PyResult>> { self.instruction - .op() + .operation .definition(&self.instruction.params) .map(|data| { QUANTUM_CIRCUIT @@ -420,36 +489,69 @@ impl DAGOpNode { #[pyclass(module = "qiskit._accelerate.circuit", extends=DAGNode)] pub struct DAGInNode { #[pyo3(get)] - wire: PyObject, + pub wire: PyObject, #[pyo3(get)] sort_key: PyObject, } +impl DAGInNode { + pub fn new(py: Python, node: NodeIndex, wire: PyObject) -> (Self, DAGNode) { + ( + DAGInNode { + wire, + sort_key: intern!(py, "[]").clone().into(), + }, + DAGNode { node: Some(node) }, + ) + } +} + #[pymethods] impl DAGInNode { #[new] - fn new(py: Python, wire: PyObject) -> PyResult<(Self, DAGNode)> { + fn py_new(py: Python, wire: PyObject) -> PyResult<(Self, DAGNode)> { Ok(( DAGInNode { wire, - sort_key: PyList::empty_bound(py).str()?.into_any().unbind(), + sort_key: intern!(py, "[]").clone().into(), }, - DAGNode { _node_id: -1 }, + DAGNode { node: None }, )) } fn __reduce__(slf: PyRef, py: Python) -> PyObject { - let state = (slf.as_ref()._node_id, &slf.sort_key); + let state = (slf.as_ref().node.map(|node| node.index()), &slf.sort_key); (py.get_type_bound::(), (&slf.wire,), state).into_py(py) } fn __setstate__(mut slf: PyRefMut, state: &Bound) -> PyResult<()> { - let (nid, sort_key): (isize, PyObject) = state.extract()?; - slf.as_mut()._node_id = nid; + let (index, sort_key): (Option, PyObject) = state.extract()?; + slf.as_mut().node = index.map(NodeIndex::new); slf.sort_key = sort_key; Ok(()) } + fn __hash__(slf: PyRef<'_, Self>, py: Python) -> PyResult { + let super_ = slf.as_ref(); + let mut hasher = AHasher::default(); + hasher.write_isize(super_.py_nid()); + hasher.write_isize(slf.wire.bind(py).hash()?); + Ok(hasher.finish()) + } + + fn __eq__(slf: PyRef, py: Python, other: &Bound) -> PyResult { + match other.downcast::() { + Ok(other) => { + let borrowed_other = other.borrow(); + let other_super = borrowed_other.as_ref(); + let super_ = slf.as_ref(); + Ok(super_.py_nid() == other_super.py_nid() + && slf.wire.bind(py).eq(borrowed_other.wire.clone_ref(py))?) + } + Err(_) => Ok(false), + } + } + /// Returns a representation of the DAGInNode fn __repr__(&self, py: Python) -> PyResult { Ok(format!("DAGInNode(wire={})", self.wire.bind(py).repr()?)) @@ -460,38 +562,71 @@ impl DAGInNode { #[pyclass(module = "qiskit._accelerate.circuit", extends=DAGNode)] pub struct DAGOutNode { #[pyo3(get)] - wire: PyObject, + pub wire: PyObject, #[pyo3(get)] sort_key: PyObject, } +impl DAGOutNode { + pub fn new(py: Python, node: NodeIndex, wire: PyObject) -> (Self, DAGNode) { + ( + DAGOutNode { + wire, + sort_key: intern!(py, "[]").clone().into(), + }, + DAGNode { node: Some(node) }, + ) + } +} + #[pymethods] impl DAGOutNode { #[new] - fn new(py: Python, wire: PyObject) -> PyResult<(Self, DAGNode)> { + fn py_new(py: Python, wire: PyObject) -> PyResult<(Self, DAGNode)> { Ok(( DAGOutNode { wire, - sort_key: PyList::empty_bound(py).str()?.into_any().unbind(), + sort_key: intern!(py, "[]").clone().into(), }, - DAGNode { _node_id: -1 }, + DAGNode { node: None }, )) } fn __reduce__(slf: PyRef, py: Python) -> PyObject { - let state = (slf.as_ref()._node_id, &slf.sort_key); + let state = (slf.as_ref().node.map(|node| node.index()), &slf.sort_key); (py.get_type_bound::(), (&slf.wire,), state).into_py(py) } fn __setstate__(mut slf: PyRefMut, state: &Bound) -> PyResult<()> { - let (nid, sort_key): (isize, PyObject) = state.extract()?; - slf.as_mut()._node_id = nid; + let (index, sort_key): (Option, PyObject) = state.extract()?; + slf.as_mut().node = index.map(NodeIndex::new); slf.sort_key = sort_key; Ok(()) } + fn __hash__(slf: PyRef<'_, Self>, py: Python) -> PyResult { + let super_ = slf.as_ref(); + let mut hasher = AHasher::default(); + hasher.write_isize(super_.py_nid()); + hasher.write_isize(slf.wire.bind(py).hash()?); + Ok(hasher.finish()) + } + /// Returns a representation of the DAGOutNode fn __repr__(&self, py: Python) -> PyResult { Ok(format!("DAGOutNode(wire={})", self.wire.bind(py).repr()?)) } + + fn __eq__(slf: PyRef, py: Python, other: &Bound) -> PyResult { + match other.downcast::() { + Ok(other) => { + let borrowed_other = other.borrow(); + let other_super = borrowed_other.as_ref(); + let super_ = slf.as_ref(); + Ok(super_.py_nid() == other_super.py_nid() + && slf.wire.bind(py).eq(borrowed_other.wire.clone_ref(py))?) + } + Err(_) => Ok(false), + } + } } diff --git a/crates/circuit/src/dot_utils.rs b/crates/circuit/src/dot_utils.rs new file mode 100644 index 000000000000..f6769c6cad11 --- /dev/null +++ b/crates/circuit/src/dot_utils.rs @@ -0,0 +1,109 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2022 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +// This module is forked from rustworkx at: +// https://github.com/Qiskit/rustworkx/blob/c4256daf96fc3c08c392450ed33bc0987cdb15ff/src/dot_utils.rs +// and has been modified to generate a dot file from a Rust DAGCircuit instead +// of a rustworkx PyGraph object + +use std::collections::BTreeMap; +use std::io::prelude::*; + +use crate::dag_circuit::{DAGCircuit, Wire}; +use pyo3::prelude::*; +use rustworkx_core::petgraph::visit::{ + EdgeRef, IntoEdgeReferences, IntoNodeReferences, NodeIndexable, NodeRef, +}; + +static TYPE: [&str; 2] = ["graph", "digraph"]; +static EDGE: [&str; 2] = ["--", "->"]; + +pub fn build_dot( + py: Python, + dag: &DAGCircuit, + file: &mut T, + graph_attrs: Option>, + node_attrs: Option, + edge_attrs: Option, +) -> PyResult<()> +where + T: Write, +{ + let graph = &dag.dag; + writeln!(file, "{} {{", TYPE[graph.is_directed() as usize])?; + if let Some(graph_attr_map) = graph_attrs { + for (key, value) in graph_attr_map.iter() { + writeln!(file, "{}={} ;", key, value)?; + } + } + + for node in graph.node_references() { + let node_weight = dag.get_node(py, node.id())?; + writeln!( + file, + "{} {};", + graph.to_index(node.id()), + attr_map_to_string(py, node_attrs.as_ref(), node_weight)? + )?; + } + for edge in graph.edge_references() { + let edge_weight = match edge.weight() { + Wire::Qubit(qubit) => dag.qubits.get(*qubit).unwrap(), + Wire::Clbit(clbit) => dag.clbits.get(*clbit).unwrap(), + Wire::Var(var) => var, + }; + writeln!( + file, + "{} {} {} {};", + graph.to_index(edge.source()), + EDGE[graph.is_directed() as usize], + graph.to_index(edge.target()), + attr_map_to_string(py, edge_attrs.as_ref(), edge_weight)? + )?; + } + writeln!(file, "}}")?; + Ok(()) +} + +static ATTRS_TO_ESCAPE: [&str; 2] = ["label", "tooltip"]; + +/// Convert an attr map to an output string +fn attr_map_to_string( + py: Python, + attrs: Option<&PyObject>, + weight: T, +) -> PyResult { + if attrs.is_none() { + return Ok("".to_string()); + } + let attr_callable = |node: T| -> PyResult> { + let res = attrs.unwrap().call1(py, (node.to_object(py),))?; + res.extract(py) + }; + + let attrs = attr_callable(weight)?; + if attrs.is_empty() { + return Ok("".to_string()); + } + let attr_string = attrs + .iter() + .map(|(key, value)| { + if ATTRS_TO_ESCAPE.contains(&key.as_str()) { + format!("{}=\"{}\"", key, value) + } else { + format!("{}={}", key, value) + } + }) + .collect::>() + .join(", "); + Ok(format!("[{}]", attr_string)) +} diff --git a/crates/circuit/src/error.rs b/crates/circuit/src/error.rs new file mode 100644 index 000000000000..b28e6b8f513b --- /dev/null +++ b/crates/circuit/src/error.rs @@ -0,0 +1,16 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use pyo3::import_exception; + +import_exception!(qiskit.dagcircuit.exceptions, DAGCircuitError); +import_exception!(qiskit.dagcircuit.exceptions, DAGDependencyError); diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index d9d439bb4745..588471546273 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -57,6 +57,7 @@ impl ImportOnceCell { } pub static BUILTIN_LIST: ImportOnceCell = ImportOnceCell::new("builtins", "list"); +pub static BUILTIN_SET: ImportOnceCell = ImportOnceCell::new("builtins", "set"); pub static OPERATION: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.operation", "Operation"); pub static INSTRUCTION: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.instruction", "Instruction"); @@ -65,6 +66,10 @@ pub static CONTROL_FLOW_OP: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.controlflow", "ControlFlowOp"); pub static QUBIT: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.quantumregister", "Qubit"); pub static CLBIT: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.classicalregister", "Clbit"); +pub static QUANTUM_REGISTER: ImportOnceCell = + ImportOnceCell::new("qiskit.circuit.quantumregister", "QuantumRegister"); +pub static CLASSICAL_REGISTER: ImportOnceCell = + ImportOnceCell::new("qiskit.circuit.classicalregister", "ClassicalRegister"); pub static PARAMETER_EXPRESSION: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.parameterexpression", "ParameterExpression"); pub static QUANTUM_CIRCUIT: ImportOnceCell = @@ -73,6 +78,17 @@ pub static SINGLETON_GATE: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.singleton", "SingletonGate"); pub static SINGLETON_CONTROLLED_GATE: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.singleton", "SingletonControlledGate"); +pub static VARIABLE_MAPPER: ImportOnceCell = + ImportOnceCell::new("qiskit.circuit._classical_resource_map", "VariableMapper"); +pub static IF_ELSE_OP: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "IfElseOp"); +pub static FOR_LOOP_OP: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "ForLoopOp"); +pub static SWITCH_CASE_OP: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "SwitchCaseOp"); +pub static WHILE_LOOP_OP: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "WhileLoopOp"); +pub static STORE_OP: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "Store"); +pub static EXPR: ImportOnceCell = ImportOnceCell::new("qiskit.circuit.classical.expr", "Expr"); +pub static ITER_VARS: ImportOnceCell = + ImportOnceCell::new("qiskit.circuit.classical.expr", "iter_vars"); +pub static DAG_NODE: ImportOnceCell = ImportOnceCell::new("qiskit.dagcircuit", "DAGNode"); pub static CONTROLLED_GATE: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "ControlledGate"); pub static ANNOTATED_OPERATION: ImportOnceCell = @@ -80,6 +96,18 @@ pub static ANNOTATED_OPERATION: ImportOnceCell = pub static DEEPCOPY: ImportOnceCell = ImportOnceCell::new("copy", "deepcopy"); pub static QI_OPERATOR: ImportOnceCell = ImportOnceCell::new("qiskit.quantum_info", "Operator"); pub static WARNINGS_WARN: ImportOnceCell = ImportOnceCell::new("warnings", "warn"); +pub static CIRCUIT_TO_DAG: ImportOnceCell = + ImportOnceCell::new("qiskit.converters", "circuit_to_dag"); +pub static DAG_TO_CIRCUIT: ImportOnceCell = + ImportOnceCell::new("qiskit.converters", "dag_to_circuit"); +pub static LEGACY_CONDITION_CHECK: ImportOnceCell = + ImportOnceCell::new("qiskit.dagcircuit.dagnode", "_legacy_condition_eq"); +pub static CONDITION_OP_CHECK: ImportOnceCell = + ImportOnceCell::new("qiskit.dagcircuit.dagnode", "_condition_op_eq"); +pub static SWITCH_CASE_OP_CHECK: ImportOnceCell = + ImportOnceCell::new("qiskit.dagcircuit.dagnode", "_switch_case_eq"); +pub static FOR_LOOP_OP_CHECK: ImportOnceCell = + ImportOnceCell::new("qiskit.dagcircuit.dagnode", "_for_loop_eq"); pub static UUID: ImportOnceCell = ImportOnceCell::new("uuid", "UUID"); /// A mapping from the enum variant in crate::operations::StandardGate to the python diff --git a/crates/circuit/src/interner.rs b/crates/circuit/src/interner.rs index f22bb80ae052..e19f56e87a7d 100644 --- a/crates/circuit/src/interner.rs +++ b/crates/circuit/src/interner.rs @@ -17,39 +17,15 @@ use hashbrown::HashMap; use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Index(u32); -pub enum InternerKey { - Index(Index), - Value(T), -} - -impl From for InternerKey { - fn from(value: Index) -> Self { - InternerKey::Index(value) - } -} - -pub struct InternerValue<'a, T> { - pub index: Index, - pub value: &'a T, -} - impl IntoPy for Index { fn into_py(self, py: Python<'_>) -> PyObject { self.0.into_py(py) } } -pub struct CacheFullError; - -impl From for PyErr { - fn from(_: CacheFullError) -> Self { - PyRuntimeError::new_err("The bit operands cache is full!") - } -} - /// An append-only data structure for interning generic /// Rust types. #[derive(Clone, Debug)] @@ -58,25 +34,20 @@ pub struct IndexedInterner { index_lookup: HashMap, Index>, } -pub trait Interner { - type Key; +pub trait Interner { type Output; /// Takes ownership of the provided key and returns the interned /// type. - fn intern(self, value: Self::Key) -> Self::Output; + fn intern(self, value: K) -> Self::Output; } -impl<'a, T> Interner for &'a IndexedInterner { - type Key = Index; - type Output = InternerValue<'a, T>; +impl<'a, T> Interner for &'a IndexedInterner { + type Output = &'a T; fn intern(self, index: Index) -> Self::Output { let value = self.entries.get(index.0 as usize).unwrap(); - InternerValue { - index, - value: value.as_ref(), - } + value.as_ref() } } @@ -84,35 +55,19 @@ impl<'a, T> Interner for &'a mut IndexedInterner where T: Eq + Hash, { - type Key = InternerKey; - type Output = Result, CacheFullError>; - - fn intern(self, key: Self::Key) -> Self::Output { - match key { - InternerKey::Index(index) => { - let value = self.entries.get(index.0 as usize).unwrap(); - Ok(InternerValue { - index, - value: value.as_ref(), - }) - } - InternerKey::Value(value) => { - if let Some(index) = self.index_lookup.get(&value).copied() { - Ok(InternerValue { - index, - value: self.entries.get(index.0 as usize).unwrap(), - }) - } else { - let args = Arc::new(value); - let index: Index = - Index(self.entries.len().try_into().map_err(|_| CacheFullError)?); - self.entries.push(args.clone()); - Ok(InternerValue { - index, - value: self.index_lookup.insert_unique_unchecked(args, index).0, - }) - } - } + type Output = PyResult; + + fn intern(self, key: T) -> Self::Output { + if let Some(index) = self.index_lookup.get(&key).copied() { + Ok(index) + } else { + let args = Arc::new(key); + let index: Index = Index(self.entries.len().try_into().map_err(|_| { + PyRuntimeError::new_err("The interner has run out of indices (cache is full)!") + })?); + self.entries.push(args.clone()); + self.index_lookup.insert_unique_unchecked(args, index); + Ok(index) } } } diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index 739bf998a611..4ca86c2ca83c 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -13,18 +13,23 @@ pub mod bit_data; pub mod circuit_data; pub mod circuit_instruction; +pub mod dag_circuit; pub mod dag_node; +mod dot_utils; +mod error; pub mod gate_matrix; pub mod imports; +mod interner; pub mod operations; pub mod packed_instruction; pub mod parameter_table; pub mod slice; pub mod util; -mod interner; +mod rustworkx_core_vnext; use pyo3::prelude::*; +use pyo3::types::{PySequence, PyTuple}; pub type BitType = u32; #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] @@ -32,6 +37,25 @@ pub struct Qubit(pub BitType); #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] pub struct Clbit(pub BitType); +pub struct TupleLikeArg<'py> { + value: Bound<'py, PyTuple>, +} + +impl<'py> FromPyObject<'py> for TupleLikeArg<'py> { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { + let value = match ob.downcast::() { + Ok(seq) => seq.to_tuple()?, + Err(_) => PyTuple::new_bound( + ob.py(), + ob.iter()? + .map(|o| Ok(o?.unbind())) + .collect::>>()?, + ), + }; + Ok(TupleLikeArg { value }) + } +} + impl From for Qubit { fn from(value: BitType) -> Self { Qubit(value) @@ -58,11 +82,12 @@ impl From for BitType { pub fn circuit(m: &Bound) -> PyResult<()> { m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; - m.add_class::()?; m.add_class::()?; Ok(()) } diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index 7134662e1ac6..ccf41d7eefb2 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -10,6 +10,7 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. +use approx::relative_eq; use std::f64::consts::PI; use crate::circuit_data::CircuitData; @@ -35,6 +36,29 @@ pub enum Param { Obj(PyObject), } +impl Param { + pub fn eq(&self, py: Python, other: &Param) -> PyResult { + match [self, other] { + [Self::Float(a), Self::Float(b)] => Ok(a == b), + [Self::Float(a), Self::ParameterExpression(b)] => b.bind(py).eq(a), + [Self::ParameterExpression(a), Self::Float(b)] => a.bind(py).eq(b), + [Self::ParameterExpression(a), Self::ParameterExpression(b)] => a.bind(py).eq(b), + [Self::Obj(_), Self::Float(_)] => Ok(false), + [Self::Float(_), Self::Obj(_)] => Ok(false), + [Self::Obj(a), Self::ParameterExpression(b)] => a.bind(py).eq(b), + [Self::Obj(a), Self::Obj(b)] => a.bind(py).eq(b), + [Self::ParameterExpression(a), Self::Obj(b)] => a.bind(py).eq(b), + } + } + + pub fn is_close(&self, py: Python, other: &Param, max_relative: f64) -> PyResult { + match [self, other] { + [Self::Float(a), Self::Float(b)] => Ok(relative_eq!(a, b, max_relative = max_relative)), + _ => self.eq(py, other), + } + } +} + impl<'py> FromPyObject<'py> for Param { fn extract_bound(b: &Bound<'py, PyAny>) -> Result { Ok(if b.is_instance(PARAMETER_EXPRESSION.get_bound(b.py()))? { @@ -131,6 +155,7 @@ pub trait Operation { /// `PackedInstruction::op`, and in turn is a view object onto a `PackedOperation`. /// /// This is the main way that we interact immutably with general circuit operations from Rust space. +#[derive(Debug)] pub enum OperationRef<'a> { Standard(StandardGate), Gate(&'a PyGate), diff --git a/crates/circuit/src/packed_instruction.rs b/crates/circuit/src/packed_instruction.rs index 9c4f19aa1ba3..7619ecb9c525 100644 --- a/crates/circuit/src/packed_instruction.rs +++ b/crates/circuit/src/packed_instruction.rs @@ -16,13 +16,18 @@ use std::ptr::NonNull; use pyo3::intern; use pyo3::prelude::*; -use pyo3::types::PyDict; +use pyo3::types::{PyDict, PyType}; +use ndarray::Array2; +use num_complex::Complex64; use smallvec::SmallVec; +use crate::circuit_data::CircuitData; use crate::circuit_instruction::ExtraInstructionAttributes; -use crate::imports::DEEPCOPY; -use crate::operations::{OperationRef, Param, PyGate, PyInstruction, PyOperation, StandardGate}; +use crate::imports::{get_std_gate_class, DEEPCOPY}; +use crate::operations::{ + Operation, OperationRef, Param, PyGate, PyInstruction, PyOperation, StandardGate, +}; /// The logical discriminant of `PackedOperation`. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -331,6 +336,78 @@ impl PackedOperation { .into()), } } + + /// Whether the Python class that we would use to represent the inner `Operation` object in + /// Python space would be an instance of the given Python type. This does not construct the + /// Python-space `Operator` instance if it can be avoided (i.e. for standard gates). + pub fn py_op_is_instance(&self, py_type: &Bound) -> PyResult { + let py = py_type.py(); + let py_op = match self.view() { + OperationRef::Standard(standard) => { + return get_std_gate_class(py, standard)? + .bind(py) + .downcast::()? + .is_subclass(py_type) + } + OperationRef::Gate(gate) => gate.gate.bind(py), + OperationRef::Instruction(instruction) => instruction.instruction.bind(py), + OperationRef::Operation(operation) => operation.operation.bind(py), + }; + py_op.is_instance(py_type) + } +} + +impl Operation for PackedOperation { + fn name(&self) -> &str { + let view = self.view(); + let name = match view { + OperationRef::Standard(ref standard) => standard.name(), + OperationRef::Gate(gate) => gate.name(), + OperationRef::Instruction(instruction) => instruction.name(), + OperationRef::Operation(operation) => operation.name(), + }; + // SAFETY: all of the inner parts of the view are owned by `self`, so it's valid for us to + // forcibly reborrowing up to our own lifetime. We avoid using `` + // just to avoid a further _potential_ unsafeness, were its implementation to start doing + // something weird with the lifetimes. `str::from_utf8_unchecked` and + // `slice::from_raw_parts` are both trivially safe because they're being called on immediate + // values from a validated `str`. + unsafe { + ::std::str::from_utf8_unchecked(::std::slice::from_raw_parts(name.as_ptr(), name.len())) + } + } + #[inline] + fn num_qubits(&self) -> u32 { + self.view().num_qubits() + } + #[inline] + fn num_clbits(&self) -> u32 { + self.view().num_clbits() + } + #[inline] + fn num_params(&self) -> u32 { + self.view().num_params() + } + #[inline] + fn control_flow(&self) -> bool { + self.view().control_flow() + } + #[inline] + fn matrix(&self, params: &[Param]) -> Option> { + self.view().matrix(params) + } + #[inline] + fn definition(&self, params: &[Param]) -> Option { + self.view().definition(params) + } + #[inline] + fn standard_gate(&self) -> Option { + self.view().standard_gate() + } + #[inline] + fn directive(&self) -> bool { + self.view().directive() + } } impl From for PackedOperation { @@ -435,15 +512,6 @@ pub struct PackedInstruction { } impl PackedInstruction { - /// Immutably view the contained operation. - /// - /// If you only care whether the contained operation is a `StandardGate` or not, you can use - /// `PackedInstruction::standard_gate`, which is a bit cheaper than this function. - #[inline] - pub fn op(&self) -> OperationRef { - self.op.view() - } - /// Access the standard gate in this `PackedInstruction`, if it is one. If the instruction /// refers to a Python-space object, `None` is returned. #[inline] @@ -469,6 +537,20 @@ impl PackedInstruction { .unwrap_or(&mut []) } + /// Does this instruction contain any compile-time symbolic `ParameterExpression`s? + pub fn is_parameterized(&self) -> bool { + self.params_view() + .iter() + .any(|x| matches!(x, Param::ParameterExpression(_))) + } + + #[inline] + pub fn condition(&self) -> Option<&Py> { + self.extra_attrs + .as_ref() + .and_then(|extra| extra.condition.as_ref()) + } + /// Build a reference to the Python-space operation object (the `Gate`, etc) packed into this /// instruction. This may construct the reference if the `PackedInstruction` is a standard /// gate with no already stored operation. @@ -510,4 +592,30 @@ impl PackedInstruction { } Ok(out) } + + /// Check equality of the operation, including Python-space checks, if appropriate. + pub fn py_op_eq(&self, py: Python, other: &Self) -> PyResult { + match (self.op.view(), other.op.view()) { + (OperationRef::Standard(left), OperationRef::Standard(right)) => Ok(left == right), + (OperationRef::Gate(left), OperationRef::Gate(right)) => { + left.gate.bind(py).eq(&right.gate) + } + (OperationRef::Instruction(left), OperationRef::Instruction(right)) => { + left.instruction.bind(py).eq(&right.instruction) + } + (OperationRef::Operation(left), OperationRef::Operation(right)) => { + left.operation.bind(py).eq(&right.operation) + } + // Handle the case we end up with a pygate for a standard gate + // this typically only happens if it's a ControlledGate in python + // and we have mutable state set. + (OperationRef::Standard(_left), OperationRef::Gate(right)) => { + self.unpack_py_op(py)?.bind(py).eq(&right.gate) + } + (OperationRef::Gate(left), OperationRef::Standard(_right)) => { + other.unpack_py_op(py)?.bind(py).eq(&left.gate) + } + _ => Ok(false), + } + } } diff --git a/crates/circuit/src/rustworkx_core_vnext.rs b/crates/circuit/src/rustworkx_core_vnext.rs new file mode 100644 index 000000000000..e69ee88a93e7 --- /dev/null +++ b/crates/circuit/src/rustworkx_core_vnext.rs @@ -0,0 +1,1417 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +// TODO: delete once we move to a version of Rustworkx which includes +// this implementation as part of rustworkx-core. +// PR: https://github.com/Qiskit/rustworkx/pull/1235 +pub mod isomorphism { + pub mod vf2 { + #![allow(clippy::too_many_arguments)] + // This module was originally forked from petgraph's isomorphism module @ v0.5.0 + // to handle PyDiGraph inputs instead of petgraph's generic Graph. However it has + // since diverged significantly from the original petgraph implementation. + + use std::cmp::{Ordering, Reverse}; + use std::convert::Infallible; + use std::error::Error; + use std::fmt::{Debug, Display, Formatter}; + use std::iter::Iterator; + use std::marker; + use std::ops::Deref; + + use hashbrown::HashMap; + use rustworkx_core::dictmap::*; + + use rustworkx_core::petgraph::data::{Build, Create, DataMap}; + use rustworkx_core::petgraph::stable_graph::NodeIndex; + use rustworkx_core::petgraph::visit::{ + Data, EdgeCount, EdgeRef, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, + IntoEdgesDirected, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, + NodeCount, NodeIndexable, + }; + use rustworkx_core::petgraph::{Directed, Incoming, Outgoing}; + + use rayon::slice::ParallelSliceMut; + + /// Returns `true` if we can map every element of `xs` to a unique + /// element of `ys` while using `matcher` func to compare two elements. + fn is_subset( + xs: &[T1], + ys: &[T2], + matcher: &mut F, + ) -> Result + where + F: FnMut(T1, T2) -> Result, + { + let mut valid = vec![true; ys.len()]; + for &a in xs { + let mut found = false; + for (&b, free) in ys.iter().zip(valid.iter_mut()) { + if *free && matcher(a, b)? { + found = true; + *free = false; + break; + } + } + + if !found { + return Ok(false); + } + } + + Ok(true) + } + + #[inline] + fn sorted(x: &mut (N, N)) { + let (a, b) = x; + if b < a { + std::mem::swap(a, b) + } + } + + /// Returns the adjacency matrix of a graph as a dictionary + /// with `(i, j)` entry equal to number of edges from node `i` to node `j`. + fn adjacency_matrix(graph: G) -> HashMap<(NodeIndex, NodeIndex), usize> + where + G: GraphProp + GraphBase + EdgeCount + IntoEdgeReferences, + { + let mut matrix = HashMap::with_capacity(graph.edge_count()); + for edge in graph.edge_references() { + let mut item = (edge.source(), edge.target()); + if !graph.is_directed() { + sorted(&mut item); + } + let entry = matrix.entry(item).or_insert(0); + *entry += 1; + } + matrix + } + + /// Returns the number of edges from node `a` to node `b`. + fn edge_multiplicity( + graph: &G, + matrix: &HashMap<(NodeIndex, NodeIndex), usize>, + a: NodeIndex, + b: NodeIndex, + ) -> usize + where + G: GraphProp + GraphBase, + { + let mut item = (a, b); + if !graph.is_directed() { + sorted(&mut item); + } + *matrix.get(&item).unwrap_or(&0) + } + + /// Nodes `a`, `b` are adjacent if the number of edges + /// from node `a` to node `b` is greater than `val`. + fn is_adjacent( + graph: &G, + matrix: &HashMap<(NodeIndex, NodeIndex), usize>, + a: NodeIndex, + b: NodeIndex, + val: usize, + ) -> bool + where + G: GraphProp + GraphBase, + { + edge_multiplicity(graph, matrix, a, b) >= val + } + + trait NodeSorter + where + G: GraphBase + DataMap + NodeCount + EdgeCount + IntoEdgeReferences, + G::NodeWeight: Clone, + G::EdgeWeight: Clone, + { + type OutputGraph: GraphBase + + Create + + Data; + + fn sort(&self, _: G) -> Vec; + + fn reorder(&self, graph: G) -> (Self::OutputGraph, HashMap) { + let order = self.sort(graph); + + let mut new_graph = + Self::OutputGraph::with_capacity(graph.node_count(), graph.edge_count()); + let mut id_map: HashMap = + HashMap::with_capacity(graph.node_count()); + for node_index in order { + let node_data = graph.node_weight(node_index).unwrap(); + let new_index = new_graph.add_node(node_data.clone()); + id_map.insert(node_index, new_index); + } + for edge in graph.edge_references() { + let edge_w = edge.weight(); + let p_index = id_map[&edge.source()]; + let c_index = id_map[&edge.target()]; + new_graph.add_edge(p_index, c_index, edge_w.clone()); + } + ( + new_graph, + id_map.iter().map(|(k, v)| (v.index(), k.index())).collect(), + ) + } + } + + /// Sort nodes based on node ids. + struct DefaultIdSorter {} + + impl DefaultIdSorter { + pub fn new() -> Self { + Self {} + } + } + + impl NodeSorter for DefaultIdSorter + where + G: Deref + + GraphBase + + DataMap + + NodeCount + + EdgeCount + + IntoEdgeReferences + + IntoNodeIdentifiers, + G::Target: GraphBase + + Data + + Create, + G::NodeWeight: Clone, + G::EdgeWeight: Clone, + { + type OutputGraph = G::Target; + fn sort(&self, graph: G) -> Vec { + graph.node_identifiers().collect() + } + } + + /// Sort nodes based on VF2++ heuristic. + struct Vf2ppSorter {} + + impl Vf2ppSorter { + pub fn new() -> Self { + Self {} + } + } + + impl NodeSorter for Vf2ppSorter + where + G: Deref + + GraphProp + + GraphBase + + DataMap + + NodeCount + + NodeIndexable + + EdgeCount + + IntoNodeIdentifiers + + IntoEdgesDirected, + G::Target: GraphBase + + Data + + Create, + G::NodeWeight: Clone, + G::EdgeWeight: Clone, + { + type OutputGraph = G::Target; + fn sort(&self, graph: G) -> Vec { + let n = graph.node_bound(); + + let dout: Vec = (0..n) + .map(|idx| { + graph + .neighbors_directed(graph.from_index(idx), Outgoing) + .count() + }) + .collect(); + + let mut din: Vec = vec![0; n]; + if graph.is_directed() { + din = (0..n) + .map(|idx| { + graph + .neighbors_directed(graph.from_index(idx), Incoming) + .count() + }) + .collect(); + } + + let mut conn_in: Vec = vec![0; n]; + let mut conn_out: Vec = vec![0; n]; + + let mut order: Vec = Vec::with_capacity(n); + + // Process BFS level + let mut process = |mut vd: Vec| -> Vec { + // repeatedly bring largest element in front. + for i in 0..vd.len() { + let (index, &item) = vd[i..] + .iter() + .enumerate() + .max_by_key(|&(_, &node)| { + ( + conn_in[node], + dout[node], + conn_out[node], + din[node], + Reverse(node), + ) + }) + .unwrap(); + + vd.swap(i, i + index); + order.push(NodeIndex::new(item)); + + for neigh in graph.neighbors_directed(graph.from_index(item), Outgoing) { + conn_in[graph.to_index(neigh)] += 1; + } + + if graph.is_directed() { + for neigh in graph.neighbors_directed(graph.from_index(item), Incoming) + { + conn_out[graph.to_index(neigh)] += 1; + } + } + } + vd + }; + + let mut seen: Vec = vec![false; n]; + + // Create BFS Tree from root and process each level. + let mut bfs_tree = |root: usize| { + if seen[root] { + return; + } + + let mut next_level: Vec = Vec::new(); + + seen[root] = true; + next_level.push(root); + while !next_level.is_empty() { + let this_level = next_level; + let this_level = process(this_level); + + next_level = Vec::new(); + for bfs_node in this_level { + for neighbor in + graph.neighbors_directed(graph.from_index(bfs_node), Outgoing) + { + let neigh = graph.to_index(neighbor); + if !seen[neigh] { + seen[neigh] = true; + next_level.push(neigh); + } + } + } + } + }; + + let mut sorted_nodes: Vec = + graph.node_identifiers().map(|node| node.index()).collect(); + sorted_nodes.par_sort_by_key(|&node| (dout[node], din[node], Reverse(node))); + sorted_nodes.reverse(); + + for node in sorted_nodes { + bfs_tree(node); + } + + order + } + } + + #[derive(Debug)] + pub struct Vf2State { + pub graph: G, + /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0, + /// NodeIndex::end() for no mapping. + mapping: Vec, + /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s) + /// These are all the next vertices that are not mapped yet, but + /// have an outgoing edge from the mapping. + out: Vec, + /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s) + /// These are all the incoming vertices, those not mapped yet, but + /// have an edge from them into the mapping. + /// Unused if graph is undirected -- it's identical with out in that case. + ins: Vec, + out_size: usize, + ins_size: usize, + adjacency_matrix: HashMap<(NodeIndex, NodeIndex), usize>, + generation: usize, + _etype: marker::PhantomData, + } + + impl Vf2State + where + G: GraphBase + GraphProp + NodeCount + EdgeCount, + for<'a> &'a G: GraphBase + + GraphProp + + NodeCount + + EdgeCount + + IntoEdgesDirected, + { + pub fn new(graph: G) -> Self { + let c0 = graph.node_count(); + let is_directed = graph.is_directed(); + let adjacency_matrix = adjacency_matrix(&graph); + Vf2State { + graph, + mapping: vec![NodeIndex::end(); c0], + out: vec![0; c0], + ins: vec![0; c0 * (is_directed as usize)], + out_size: 0, + ins_size: 0, + adjacency_matrix, + generation: 0, + _etype: marker::PhantomData, + } + } + + /// Return **true** if we have a complete mapping + pub fn is_complete(&self) -> bool { + self.generation == self.mapping.len() + } + + /// Add mapping **from** <-> **to** to the state. + pub fn push_mapping(&mut self, from: NodeIndex, to: NodeIndex) { + self.generation += 1; + let s = self.generation; + self.mapping[from.index()] = to; + // update T0 & T1 ins/outs + // T0out: Node in G0 not in M0 but successor of a node in M0. + // st.out[0]: Node either in M0 or successor of M0 + for ix in self.graph.neighbors(from) { + if self.out[ix.index()] == 0 { + self.out[ix.index()] = s; + self.out_size += 1; + } + } + if self.graph.is_directed() { + for ix in self.graph.neighbors_directed(from, Incoming) { + if self.ins[ix.index()] == 0 { + self.ins[ix.index()] = s; + self.ins_size += 1; + } + } + } + } + + /// Restore the state to before the last added mapping + pub fn pop_mapping(&mut self, from: NodeIndex) { + let s = self.generation; + self.generation -= 1; + + // undo (n, m) mapping + self.mapping[from.index()] = NodeIndex::end(); + + // unmark in ins and outs + for ix in self.graph.neighbors(from) { + if self.out[ix.index()] == s { + self.out[ix.index()] = 0; + self.out_size -= 1; + } + } + if self.graph.is_directed() { + for ix in self.graph.neighbors_directed(from, Incoming) { + if self.ins[ix.index()] == s { + self.ins[ix.index()] = 0; + self.ins_size -= 1; + } + } + } + } + + /// Find the next (least) node in the Tout set. + pub fn next_out_index(&self, from_index: usize) -> Option { + self.out[from_index..] + .iter() + .enumerate() + .find(move |&(index, elt)| { + *elt > 0 && self.mapping[from_index + index] == NodeIndex::end() + }) + .map(|(index, _)| index) + } + + /// Find the next (least) node in the Tin set. + pub fn next_in_index(&self, from_index: usize) -> Option { + self.ins[from_index..] + .iter() + .enumerate() + .find(move |&(index, elt)| { + *elt > 0 && self.mapping[from_index + index] == NodeIndex::end() + }) + .map(|(index, _)| index) + } + + /// Find the next (least) node in the N - M set. + pub fn next_rest_index(&self, from_index: usize) -> Option { + self.mapping[from_index..] + .iter() + .enumerate() + .find(|&(_, elt)| *elt == NodeIndex::end()) + .map(|(index, _)| index) + } + } + + #[derive(Debug)] + pub enum IsIsomorphicError { + NodeMatcherErr(NME), + EdgeMatcherErr(EME), + } + + impl Display for IsIsomorphicError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + IsIsomorphicError::NodeMatcherErr(e) => { + write!(f, "Node match callback failed with: {}", e) + } + IsIsomorphicError::EdgeMatcherErr(e) => { + write!(f, "Edge match callback failed with: {}", e) + } + } + } + } + + impl Error for IsIsomorphicError {} + + pub struct NoSemanticMatch; + + pub trait NodeMatcher { + type Error; + fn enabled(&self) -> bool; + fn eq( + &mut self, + _g0: &G0, + _g1: &G1, + _n0: G0::NodeId, + _n1: G1::NodeId, + ) -> Result; + } + + impl NodeMatcher for NoSemanticMatch { + type Error = Infallible; + #[inline] + fn enabled(&self) -> bool { + false + } + #[inline] + fn eq( + &mut self, + _g0: &G0, + _g1: &G1, + _n0: G0::NodeId, + _n1: G1::NodeId, + ) -> Result { + Ok(true) + } + } + + impl NodeMatcher for F + where + G0: GraphBase + DataMap, + G1: GraphBase + DataMap, + F: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> Result, + { + type Error = E; + #[inline] + fn enabled(&self) -> bool { + true + } + #[inline] + fn eq( + &mut self, + g0: &G0, + g1: &G1, + n0: G0::NodeId, + n1: G1::NodeId, + ) -> Result { + if let (Some(x), Some(y)) = (g0.node_weight(n0), g1.node_weight(n1)) { + self(x, y) + } else { + Ok(false) + } + } + } + + pub trait EdgeMatcher { + type Error; + fn enabled(&self) -> bool; + fn eq( + &mut self, + _g0: &G0, + _g1: &G1, + e0: G0::EdgeId, + e1: G1::EdgeId, + ) -> Result; + } + + impl EdgeMatcher for NoSemanticMatch { + type Error = Infallible; + #[inline] + fn enabled(&self) -> bool { + false + } + #[inline] + fn eq( + &mut self, + _g0: &G0, + _g1: &G1, + _e0: G0::EdgeId, + _e1: G1::EdgeId, + ) -> Result { + Ok(true) + } + } + + impl EdgeMatcher for F + where + G0: GraphBase + DataMap, + G1: GraphBase + DataMap, + F: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> Result, + { + type Error = E; + #[inline] + fn enabled(&self) -> bool { + true + } + #[inline] + fn eq( + &mut self, + g0: &G0, + g1: &G1, + e0: G0::EdgeId, + e1: G1::EdgeId, + ) -> Result { + if let (Some(x), Some(y)) = (g0.edge_weight(e0), g1.edge_weight(e1)) { + self(x, y) + } else { + Ok(false) + } + } + } + + /// [Graph] Return `true` if the graphs `g0` and `g1` are (sub) graph isomorphic. + /// + /// Using the VF2 algorithm, examining both syntactic and semantic + /// graph isomorphism (graph structure and matching node and edge weights). + /// + /// The graphs should not be multigraphs. + pub fn is_isomorphic( + g0: &G0, + g1: &G1, + node_match: NM, + edge_match: EM, + id_order: bool, + ordering: Ordering, + induced: bool, + call_limit: Option, + ) -> Result> + where + G0: GraphProp + + GraphBase + + DataMap + + Create + + NodeCount + + EdgeCount, + for<'a> &'a G0: GraphBase + + Data + + NodeIndexable + + IntoEdgesDirected + + IntoNodeIdentifiers, + G0::NodeWeight: Clone, + G0::EdgeWeight: Clone, + G1: GraphProp + + GraphBase + + DataMap + + Create + + NodeCount + + EdgeCount, + for<'a> &'a G1: GraphBase + + Data + + NodeIndexable + + IntoEdgesDirected + + IntoNodeIdentifiers, + G1::NodeWeight: Clone, + G1::EdgeWeight: Clone, + NM: NodeMatcher, + EM: EdgeMatcher, + { + if (g0.node_count().cmp(&g1.node_count()).then(ordering) != ordering) + || (g0.edge_count().cmp(&g1.edge_count()).then(ordering) != ordering) + { + return Ok(false); + } + + let mut vf2 = Vf2Algorithm::new( + g0, g1, node_match, edge_match, id_order, ordering, induced, call_limit, + ); + + match vf2.next() { + Some(Ok(_)) => Ok(true), + Some(Err(e)) => Err(e), + None => Ok(false), + } + } + + #[derive(Copy, Clone, PartialEq, Debug)] + enum OpenList { + Out, + In, + Other, + } + + #[derive(Clone, PartialEq, Debug)] + enum Frame { + Outer, + Inner { nodes: [N; 2], open_list: OpenList }, + Unwind { nodes: [N; 2], open_list: OpenList }, + } + + /// An iterator which uses the VF2(++) algorithm to produce isomorphic matches + /// between two graphs, examining both syntactic and semantic graph isomorphism + /// (graph structure and matching node and edge weights). + /// + /// The graphs should not be multigraphs. + pub struct Vf2Algorithm + where + G0: GraphBase + Data, + G1: GraphBase + Data, + NM: NodeMatcher, + EM: EdgeMatcher, + { + pub st: (Vf2State, Vf2State), + pub node_match: NM, + pub edge_match: EM, + ordering: Ordering, + induced: bool, + node_map_g0: HashMap, + node_map_g1: HashMap, + stack: Vec>, + call_limit: Option, + _counter: usize, + } + + impl Vf2Algorithm + where + G0: GraphProp + + GraphBase + + DataMap + + Create + + NodeCount + + EdgeCount, + for<'a> &'a G0: GraphBase + + Data + + NodeIndexable + + IntoEdgesDirected + + IntoNodeIdentifiers, + G0::NodeWeight: Clone, + G0::EdgeWeight: Clone, + G1: GraphProp + + GraphBase + + DataMap + + Create + + NodeCount + + EdgeCount, + for<'a> &'a G1: GraphBase + + Data + + NodeIndexable + + IntoEdgesDirected + + IntoNodeIdentifiers, + G1::NodeWeight: Clone, + G1::EdgeWeight: Clone, + NM: NodeMatcher, + EM: EdgeMatcher, + { + pub fn new( + g0: &G0, + g1: &G1, + node_match: NM, + edge_match: EM, + id_order: bool, + ordering: Ordering, + induced: bool, + call_limit: Option, + ) -> Self { + let (g0, node_map_g0) = if id_order { + DefaultIdSorter::new().reorder(g0) + } else { + Vf2ppSorter::new().reorder(g0) + }; + + let (g1, node_map_g1) = if id_order { + DefaultIdSorter::new().reorder(g1) + } else { + Vf2ppSorter::new().reorder(g1) + }; + + let st = (Vf2State::new(g0), Vf2State::new(g1)); + Vf2Algorithm { + st, + node_match, + edge_match, + ordering, + induced, + node_map_g0, + node_map_g1, + stack: vec![Frame::Outer], + call_limit, + _counter: 0, + } + } + + fn mapping(&self) -> DictMap { + let mut mapping: DictMap = DictMap::new(); + self.st + .1 + .mapping + .iter() + .enumerate() + .for_each(|(index, val)| { + mapping.insert(self.node_map_g0[&val.index()], self.node_map_g1[&index]); + }); + + mapping + } + + fn next_candidate( + st: &mut (Vf2State, Vf2State), + ) -> Option<(NodeIndex, NodeIndex, OpenList)> { + // Try the out list + let mut to_index = st.1.next_out_index(0); + let mut from_index = None; + let mut open_list = OpenList::Out; + + if to_index.is_some() { + from_index = st.0.next_out_index(0); + open_list = OpenList::Out; + } + // Try the in list + if to_index.is_none() || from_index.is_none() { + to_index = st.1.next_in_index(0); + + if to_index.is_some() { + from_index = st.0.next_in_index(0); + open_list = OpenList::In; + } + } + // Try the other list -- disconnected graph + if to_index.is_none() || from_index.is_none() { + to_index = st.1.next_rest_index(0); + if to_index.is_some() { + from_index = st.0.next_rest_index(0); + open_list = OpenList::Other; + } + } + match (from_index, to_index) { + (Some(n), Some(m)) => Some((NodeIndex::new(n), NodeIndex::new(m), open_list)), + // No more candidates + _ => None, + } + } + + fn next_from_ix( + st: &mut (Vf2State, Vf2State), + nx: NodeIndex, + open_list: OpenList, + ) -> Option { + // Find the next node index to try on the `from` side of the mapping + let start = nx.index() + 1; + let cand0 = match open_list { + OpenList::Out => st.0.next_out_index(start), + OpenList::In => st.0.next_in_index(start), + OpenList::Other => st.0.next_rest_index(start), + } + .map(|c| c + start); // compensate for start offset. + match cand0 { + None => None, // no more candidates + Some(ix) => { + debug_assert!(ix >= start); + Some(NodeIndex::new(ix)) + } + } + } + + fn pop_state(st: &mut (Vf2State, Vf2State), nodes: [NodeIndex; 2]) { + // Restore state. + st.0.pop_mapping(nodes[0]); + st.1.pop_mapping(nodes[1]); + } + + fn push_state(st: &mut (Vf2State, Vf2State), nodes: [NodeIndex; 2]) { + // Add mapping nx <-> mx to the state + st.0.push_mapping(nodes[0], nodes[1]); + st.1.push_mapping(nodes[1], nodes[0]); + } + + fn is_feasible( + st: &mut (Vf2State, Vf2State), + nodes: [NodeIndex; 2], + node_match: &mut NM, + edge_match: &mut EM, + ordering: Ordering, + induced: bool, + ) -> Result> { + // Check syntactic feasibility of mapping by ensuring adjacencies + // of nx map to adjacencies of mx. + // + // nx == map to => mx + // + // R_succ + // + // Check that every neighbor of nx is mapped to a neighbor of mx, + // then check the reverse, from mx to nx. Check that they have the same + // count of edges. + // + // Note: We want to check the lookahead measures here if we can, + // R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred + // R_in: Same with Tin + // R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred, + // Ñ is G0 - M - Tin - Tout + let end = NodeIndex::end(); + let mut succ_count = [0, 0]; + for n_neigh in st.0.graph.neighbors(nodes[0]) { + succ_count[0] += 1; + if !induced { + continue; + } + // handle the self loop case; it's not in the mapping (yet) + let m_neigh = if nodes[0] != n_neigh { + st.0.mapping[n_neigh.index()] + } else { + nodes[1] + }; + if m_neigh == end { + continue; + } + let val = + edge_multiplicity(&st.0.graph, &st.0.adjacency_matrix, nodes[0], n_neigh); + + let has_edge = + is_adjacent(&st.1.graph, &st.1.adjacency_matrix, nodes[1], m_neigh, val); + if !has_edge { + return Ok(false); + } + } + + for n_neigh in st.1.graph.neighbors(nodes[1]) { + succ_count[1] += 1; + // handle the self loop case; it's not in the mapping (yet) + let m_neigh = if nodes[1] != n_neigh { + st.1.mapping[n_neigh.index()] + } else { + nodes[0] + }; + if m_neigh == end { + continue; + } + let val = + edge_multiplicity(&st.1.graph, &st.1.adjacency_matrix, nodes[1], n_neigh); + + let has_edge = + is_adjacent(&st.0.graph, &st.0.adjacency_matrix, nodes[0], m_neigh, val); + if !has_edge { + return Ok(false); + } + } + if succ_count[0].cmp(&succ_count[1]).then(ordering) != ordering { + return Ok(false); + } + // R_pred + if st.0.graph.is_directed() { + let mut pred_count = [0, 0]; + for n_neigh in st.0.graph.neighbors_directed(nodes[0], Incoming) { + pred_count[0] += 1; + if !induced { + continue; + } + // the self loop case is handled in outgoing + let m_neigh = st.0.mapping[n_neigh.index()]; + if m_neigh == end { + continue; + } + let val = edge_multiplicity( + &st.0.graph, + &st.0.adjacency_matrix, + n_neigh, + nodes[0], + ); + + let has_edge = is_adjacent( + &st.1.graph, + &st.1.adjacency_matrix, + m_neigh, + nodes[1], + val, + ); + if !has_edge { + return Ok(false); + } + } + + for n_neigh in st.1.graph.neighbors_directed(nodes[1], Incoming) { + pred_count[1] += 1; + // the self loop case is handled in outgoing + let m_neigh = st.1.mapping[n_neigh.index()]; + if m_neigh == end { + continue; + } + let val = edge_multiplicity( + &st.1.graph, + &st.1.adjacency_matrix, + n_neigh, + nodes[1], + ); + + let has_edge = is_adjacent( + &st.0.graph, + &st.0.adjacency_matrix, + m_neigh, + nodes[0], + val, + ); + if !has_edge { + return Ok(false); + } + } + if pred_count[0].cmp(&pred_count[1]).then(ordering) != ordering { + return Ok(false); + } + } + macro_rules! field { + ($x:ident, 0) => { + $x.0 + }; + ($x:ident, 1) => { + $x.1 + }; + ($x:ident, 1 - 0) => { + $x.1 + }; + ($x:ident, 1 - 1) => { + $x.0 + }; + } + macro_rules! rule { + ($arr:ident, $j:tt, $dir:expr) => {{ + let mut count = 0; + for n_neigh in field!(st, $j).graph.neighbors_directed(nodes[$j], $dir) { + let index = n_neigh.index(); + if field!(st, $j).$arr[index] > 0 && st.$j.mapping[index] == end { + count += 1; + } + } + count + }}; + } + // R_out + if rule!(out, 0, Outgoing) + .cmp(&rule!(out, 1, Outgoing)) + .then(ordering) + != ordering + { + return Ok(false); + } + if st.0.graph.is_directed() + && rule!(out, 0, Incoming) + .cmp(&rule!(out, 1, Incoming)) + .then(ordering) + != ordering + { + return Ok(false); + } + // R_in + if st.0.graph.is_directed() { + if rule!(ins, 0, Outgoing) + .cmp(&rule!(ins, 1, Outgoing)) + .then(ordering) + != ordering + { + return Ok(false); + } + + if rule!(ins, 0, Incoming) + .cmp(&rule!(ins, 1, Incoming)) + .then(ordering) + != ordering + { + return Ok(false); + } + } + // R_new + if induced { + let mut new_count = [0, 0]; + for n_neigh in st.0.graph.neighbors(nodes[0]) { + let index = n_neigh.index(); + if st.0.out[index] == 0 && (st.0.ins.is_empty() || st.0.ins[index] == 0) { + new_count[0] += 1; + } + } + for n_neigh in st.1.graph.neighbors(nodes[1]) { + let index = n_neigh.index(); + if st.1.out[index] == 0 && (st.1.ins.is_empty() || st.1.ins[index] == 0) { + new_count[1] += 1; + } + } + if new_count[0].cmp(&new_count[1]).then(ordering) != ordering { + return Ok(false); + } + if st.0.graph.is_directed() { + let mut new_count = [0, 0]; + for n_neigh in st.0.graph.neighbors_directed(nodes[0], Incoming) { + let index = n_neigh.index(); + if st.0.out[index] == 0 && st.0.ins[index] == 0 { + new_count[0] += 1; + } + } + for n_neigh in st.1.graph.neighbors_directed(nodes[1], Incoming) { + let index = n_neigh.index(); + if st.1.out[index] == 0 && st.1.ins[index] == 0 { + new_count[1] += 1; + } + } + if new_count[0].cmp(&new_count[1]).then(ordering) != ordering { + return Ok(false); + } + } + } + // semantic feasibility: compare associated data for nodes + if node_match.enabled() + && !node_match + .eq(&st.0.graph, &st.1.graph, nodes[0], nodes[1]) + .map_err(IsIsomorphicError::NodeMatcherErr)? + { + return Ok(false); + } + // semantic feasibility: compare associated data for edges + if edge_match.enabled() { + let mut matcher = + |g0_edge: (NodeIndex, G0::EdgeId), + g1_edge: (NodeIndex, G1::EdgeId)| + -> Result> { + let (nx, e0) = g0_edge; + let (mx, e1) = g1_edge; + if nx == mx + && edge_match + .eq(&st.0.graph, &st.1.graph, e0, e1) + .map_err(IsIsomorphicError::EdgeMatcherErr)? + { + return Ok(true); + } + Ok(false) + }; + + // Used to reverse the order of edge args to the matcher + // when checking G1 subset of G0. + #[inline] + fn reverse_args(mut f: F) -> impl FnMut(T2, T1) -> R + where + F: FnMut(T1, T2) -> R, + { + move |y, x| f(x, y) + } + + // outgoing edges + if induced { + let e_first: Vec<(NodeIndex, G0::EdgeId)> = + st.0.graph + .edges(nodes[0]) + .filter_map(|edge| { + let n_neigh = edge.target(); + let m_neigh = if nodes[0] != n_neigh { + st.0.mapping[n_neigh.index()] + } else { + nodes[1] + }; + if m_neigh == end { + return None; + } + Some((m_neigh, edge.id())) + }) + .collect(); + + let e_second: Vec<(NodeIndex, G1::EdgeId)> = + st.1.graph + .edges(nodes[1]) + .map(|edge| (edge.target(), edge.id())) + .collect(); + + if !is_subset(&e_first, &e_second, &mut matcher)? { + return Ok(false); + }; + } + + let e_first: Vec<(NodeIndex, G1::EdgeId)> = + st.1.graph + .edges(nodes[1]) + .filter_map(|edge| { + let n_neigh = edge.target(); + let m_neigh = if nodes[1] != n_neigh { + st.1.mapping[n_neigh.index()] + } else { + nodes[0] + }; + if m_neigh == end { + return None; + } + Some((m_neigh, edge.id())) + }) + .collect(); + + let e_second: Vec<(NodeIndex, G0::EdgeId)> = + st.0.graph + .edges(nodes[0]) + .map(|edge| (edge.target(), edge.id())) + .collect(); + + if !is_subset(&e_first, &e_second, &mut reverse_args(&mut matcher))? { + return Ok(false); + }; + + // incoming edges + if st.0.graph.is_directed() { + if induced { + let e_first: Vec<(NodeIndex, G0::EdgeId)> = + st.0.graph + .edges_directed(nodes[0], Incoming) + .filter_map(|edge| { + let n_neigh = edge.source(); + let m_neigh = if nodes[0] != n_neigh { + st.0.mapping[n_neigh.index()] + } else { + nodes[1] + }; + if m_neigh == end { + return None; + } + Some((m_neigh, edge.id())) + }) + .collect(); + + let e_second: Vec<(NodeIndex, G1::EdgeId)> = + st.1.graph + .edges_directed(nodes[1], Incoming) + .map(|edge| (edge.source(), edge.id())) + .collect(); + + if !is_subset(&e_first, &e_second, &mut matcher)? { + return Ok(false); + }; + } + + let e_first: Vec<(NodeIndex, G1::EdgeId)> = + st.1.graph + .edges_directed(nodes[1], Incoming) + .filter_map(|edge| { + let n_neigh = edge.source(); + let m_neigh = if nodes[1] != n_neigh { + st.1.mapping[n_neigh.index()] + } else { + nodes[0] + }; + if m_neigh == end { + return None; + } + Some((m_neigh, edge.id())) + }) + .collect(); + + let e_second: Vec<(NodeIndex, G0::EdgeId)> = + st.0.graph + .edges_directed(nodes[0], Incoming) + .map(|edge| (edge.source(), edge.id())) + .collect(); + + if !is_subset(&e_first, &e_second, &mut reverse_args(&mut matcher))? { + return Ok(false); + }; + } + } + Ok(true) + } + } + + impl Iterator for Vf2Algorithm + where + G0: GraphProp + + GraphBase + + DataMap + + Create + + NodeCount + + EdgeCount, + for<'a> &'a G0: GraphBase + + Data + + NodeIndexable + + IntoEdgesDirected + + IntoNodeIdentifiers, + G0::NodeWeight: Clone, + G0::EdgeWeight: Clone, + G1: GraphProp + + GraphBase + + DataMap + + Create + + NodeCount + + EdgeCount, + for<'a> &'a G1: GraphBase + + Data + + NodeIndexable + + IntoEdgesDirected + + IntoNodeIdentifiers, + G1::NodeWeight: Clone, + G1::EdgeWeight: Clone, + NM: NodeMatcher, + EM: EdgeMatcher, + { + type Item = Result, IsIsomorphicError>; + + /// Return Some(mapping) if isomorphism is decided, else None. + fn next(&mut self) -> Option { + if (self + .st + .0 + .graph + .node_count() + .cmp(&self.st.1.graph.node_count()) + .then(self.ordering) + != self.ordering) + || (self + .st + .0 + .graph + .edge_count() + .cmp(&self.st.1.graph.edge_count()) + .then(self.ordering) + != self.ordering) + { + return None; + } + + // A "depth first" search of a valid mapping from graph 1 to graph 2 + + // F(s, n, m) -- evaluate state s and add mapping n <-> m + + // Find least T1out node (in st.out[1] but not in M[1]) + while let Some(frame) = self.stack.pop() { + match frame { + Frame::Unwind { + nodes, + open_list: ol, + } => { + Vf2Algorithm::::pop_state(&mut self.st, nodes); + + match Vf2Algorithm::::next_from_ix( + &mut self.st, + nodes[0], + ol, + ) { + None => continue, + Some(nx) => { + let f = Frame::Inner { + nodes: [nx, nodes[1]], + open_list: ol, + }; + self.stack.push(f); + } + } + } + Frame::Outer => { + match Vf2Algorithm::::next_candidate(&mut self.st) { + None => { + if self.st.1.is_complete() { + return Some(Ok(self.mapping())); + } + continue; + } + Some((nx, mx, ol)) => { + let f = Frame::Inner { + nodes: [nx, mx], + open_list: ol, + }; + self.stack.push(f); + } + } + } + Frame::Inner { + nodes, + open_list: ol, + } => { + let feasible = match Vf2Algorithm::::is_feasible( + &mut self.st, + nodes, + &mut self.node_match, + &mut self.edge_match, + self.ordering, + self.induced, + ) { + Ok(f) => f, + Err(e) => { + return Some(Err(e)); + } + }; + + if feasible { + Vf2Algorithm::::push_state(&mut self.st, nodes); + // Check cardinalities of Tin, Tout sets + if self + .st + .0 + .out_size + .cmp(&self.st.1.out_size) + .then(self.ordering) + == self.ordering + && self + .st + .0 + .ins_size + .cmp(&self.st.1.ins_size) + .then(self.ordering) + == self.ordering + { + self._counter += 1; + if let Some(limit) = self.call_limit { + if self._counter > limit { + return None; + } + } + let f0 = Frame::Unwind { + nodes, + open_list: ol, + }; + + self.stack.push(f0); + self.stack.push(Frame::Outer); + continue; + } + Vf2Algorithm::::pop_state(&mut self.st, nodes); + } + match Vf2Algorithm::::next_from_ix( + &mut self.st, + nodes[0], + ol, + ) { + None => continue, + Some(nx) => { + let f = Frame::Inner { + nodes: [nx, nodes[1]], + open_list: ol, + }; + self.stack.push(f); + } + } + } + } + } + None + } + } + } +} diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index 10a48df99778..a330b8cbd682 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -12,7 +12,8 @@ """Helper function for converting a circuit to a dag""" -from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode +from qiskit.dagcircuit.dagcircuit import DAGCircuit +from qiskit.dagcircuit.dagnode import DAGOpNode def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_order=None): @@ -93,7 +94,7 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord for instruction in circuit.data: dagcircuit._apply_op_node_back( - DAGOpNode.from_instruction(instruction, dag=dagcircuit, deepcopy=copy_operations) + DAGOpNode.from_instruction(instruction, deepcopy=copy_operations) ) dagcircuit.duration = circuit.duration diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 53cbc6f8f7f1..8738c2676a14 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -20,2406 +20,5 @@ composed, and modified. Some natural properties like depth can be computed directly from the graph. """ -from __future__ import annotations -import copy -import enum -import itertools -import math -from collections import OrderedDict, defaultdict, deque, namedtuple -from collections.abc import Callable, Sequence, Generator, Iterable -from typing import Any, Literal - -import numpy as np -import rustworkx as rx - -from qiskit.circuit import ( - ControlFlowOp, - ForLoopOp, - IfElseOp, - WhileLoopOp, - SwitchCaseOp, - _classical_resource_map, - Operation, - Store, -) -from qiskit.circuit.classical import expr -from qiskit.circuit.controlflow import condition_resources, node_resources, CONTROL_FLOW_OP_NAMES -from qiskit.circuit.quantumregister import QuantumRegister, Qubit -from qiskit.circuit.classicalregister import ClassicalRegister, Clbit -from qiskit.circuit.gate import Gate -from qiskit.circuit.instruction import Instruction -from qiskit.circuit.parameterexpression import ParameterExpression -from qiskit.dagcircuit.exceptions import DAGCircuitError -from qiskit.dagcircuit.dagnode import DAGNode, DAGOpNode, DAGInNode, DAGOutNode -from qiskit.circuit.bit import Bit -from qiskit.pulse import Schedule -from qiskit._accelerate.euler_one_qubit_decomposer import collect_1q_runs_filter -from qiskit._accelerate.convert_2q_block_matrix import collect_2q_blocks_filter - -BitLocations = namedtuple("BitLocations", ("index", "registers")) -# The allowable arguments to :meth:`DAGCircuit.copy_empty_like`'s ``vars_mode``. -_VarsMode = Literal["alike", "captures", "drop"] - - -class DAGCircuit: - """ - Quantum circuit as a directed acyclic graph. - - There are 3 types of nodes in the graph: inputs, outputs, and operations. - The nodes are connected by directed edges that correspond to qubits and - bits. - """ - - # pylint: disable=invalid-name - - def __init__(self): - """Create an empty circuit.""" - - # Circuit name. Generally, this corresponds to the name - # of the QuantumCircuit from which the DAG was generated. - self.name = None - - # Circuit metadata - self.metadata = {} - - # Cache of dag op node sort keys - self._key_cache = {} - - # Set of wire data in the DAG. A wire is an owned unit of data. Qubits are the primary - # wire type (and the only data that has _true_ wire properties from a read/write - # perspective), but clbits and classical `Var`s are too. Note: classical registers are - # _not_ wires because the individual bits are the more fundamental unit. We treat `Var`s - # as the entire wire (as opposed to individual bits of them) for scalability reasons; if a - # parametric program wants to parametrize over 16-bit angles, we can't scale to 1000s of - # those by tracking all 16 bits individually. - # - # Classical variables shouldn't be "wires"; it should be possible to have multiple reads - # without implying ordering. The initial addition of the classical variables uses the - # existing wire structure as an MVP; we expect to handle this better in a new version of the - # transpiler IR that also handles control flow more properly. - self._wires = set() - - # Map from wire to input nodes of the graph - self.input_map = OrderedDict() - - # Map from wire to output nodes of the graph - self.output_map = OrderedDict() - - # Directed multigraph whose nodes are inputs, outputs, or operations. - # Operation nodes have equal in- and out-degrees and carry - # additional data about the operation, including the argument order - # and parameter values. - # Input nodes have out-degree 1 and output nodes have in-degree 1. - # Edges carry wire labels and each operation has - # corresponding in- and out-edges with the same wire labels. - self._multi_graph = rx.PyDAG() - - # Map of qreg/creg name to Register object. - self.qregs = OrderedDict() - self.cregs = OrderedDict() - - # List of Qubit/Clbit wires that the DAG acts on. - self.qubits: list[Qubit] = [] - self.clbits: list[Clbit] = [] - - # Dictionary mapping of Qubit and Clbit instances to a tuple comprised of - # 0) corresponding index in dag.{qubits,clbits} and - # 1) a list of Register-int pairs for each Register containing the Bit and - # its index within that register. - self._qubit_indices: dict[Qubit, BitLocations] = {} - self._clbit_indices: dict[Clbit, BitLocations] = {} - # Tracking for the classical variables used in the circuit. This contains the information - # needed to insert new nodes. This is keyed by the name rather than the `Var` instance - # itself so we can ensure we don't allow shadowing or redefinition of names. - self._vars_info: dict[str, _DAGVarInfo] = {} - # Convenience stateful tracking for the individual types of nodes to allow things like - # comparisons between circuits to take place without needing to disambiguate the - # graph-specific usage information. - self._vars_by_type: dict[_DAGVarType, set[expr.Var]] = { - type_: set() for type_ in _DAGVarType - } - - self._global_phase: float | ParameterExpression = 0.0 - self._calibrations: dict[str, dict[tuple, Schedule]] = defaultdict(dict) - - self._op_names = {} - - self.duration = None - self.unit = "dt" - - @property - def wires(self): - """Return a list of the wires in order.""" - return ( - self.qubits - + self.clbits - + [var for vars in self._vars_by_type.values() for var in vars] - ) - - @property - def node_counter(self): - """ - Returns the number of nodes in the dag. - """ - return len(self._multi_graph) - - @property - def global_phase(self): - """Return the global phase of the circuit.""" - return self._global_phase - - @global_phase.setter - def global_phase(self, angle: float | ParameterExpression): - """Set the global phase of the circuit. - - Args: - angle (float, ParameterExpression) - """ - if isinstance(angle, ParameterExpression): - self._global_phase = angle - else: - # Set the phase to the [0, 2π) interval - angle = float(angle) - if not angle: - self._global_phase = 0 - else: - self._global_phase = angle % (2 * math.pi) - - @property - def calibrations(self) -> dict[str, dict[tuple, Schedule]]: - """Return calibration dictionary. - - The custom pulse definition of a given gate is of the form - {'gate_name': {(qubits, params): schedule}} - """ - return dict(self._calibrations) - - @calibrations.setter - def calibrations(self, calibrations: dict[str, dict[tuple, Schedule]]): - """Set the circuit calibration data from a dictionary of calibration definition. - - Args: - calibrations (dict): A dictionary of input in the format - {'gate_name': {(qubits, gate_params): schedule}} - """ - self._calibrations = defaultdict(dict, calibrations) - - def add_calibration(self, gate, qubits, schedule, params=None): - """Register a low-level, custom pulse definition for the given gate. - - Args: - gate (Union[Gate, str]): Gate information. - qubits (Union[int, Tuple[int]]): List of qubits to be measured. - schedule (Schedule): Schedule information. - params (Optional[List[Union[float, Parameter]]]): A list of parameters. - - Raises: - Exception: if the gate is of type string and params is None. - """ - - def _format(operand): - try: - # Using float/complex value as a dict key is not good idea. - # This makes the mapping quite sensitive to the rounding error. - # However, the mechanism is already tied to the execution model (i.e. pulse gate) - # and we cannot easily update this rule. - # The same logic exists in QuantumCircuit.add_calibration. - evaluated = complex(operand) - if np.isreal(evaluated): - evaluated = float(evaluated.real) - if evaluated.is_integer(): - evaluated = int(evaluated) - return evaluated - except TypeError: - # Unassigned parameter - return operand - - if isinstance(gate, Gate): - params = gate.params - gate = gate.name - if params is not None: - params = tuple(map(_format, params)) - else: - params = () - - self._calibrations[gate][(tuple(qubits), params)] = schedule - - def has_calibration_for(self, node): - """Return True if the dag has a calibration defined for the node operation. In this - case, the operation does not need to be translated to the device basis. - """ - if not self.calibrations or node.op.name not in self.calibrations: - return False - qubits = tuple(self.qubits.index(qubit) for qubit in node.qargs) - params = [] - for p in node.op.params: - if isinstance(p, ParameterExpression) and not p.parameters: - params.append(float(p)) - else: - params.append(p) - params = tuple(params) - return (qubits, params) in self.calibrations[node.op.name] - - def remove_all_ops_named(self, opname): - """Remove all operation nodes with the given name.""" - for n in self.named_nodes(opname): - self.remove_op_node(n) - - def add_qubits(self, qubits): - """Add individual qubit wires.""" - if any(not isinstance(qubit, Qubit) for qubit in qubits): - raise DAGCircuitError("not a Qubit instance.") - - duplicate_qubits = set(self.qubits).intersection(qubits) - if duplicate_qubits: - raise DAGCircuitError(f"duplicate qubits {duplicate_qubits}") - - for qubit in qubits: - self.qubits.append(qubit) - self._qubit_indices[qubit] = BitLocations(len(self.qubits) - 1, []) - self._add_wire(qubit) - - def add_clbits(self, clbits): - """Add individual clbit wires.""" - if any(not isinstance(clbit, Clbit) for clbit in clbits): - raise DAGCircuitError("not a Clbit instance.") - - duplicate_clbits = set(self.clbits).intersection(clbits) - if duplicate_clbits: - raise DAGCircuitError(f"duplicate clbits {duplicate_clbits}") - - for clbit in clbits: - self.clbits.append(clbit) - self._clbit_indices[clbit] = BitLocations(len(self.clbits) - 1, []) - self._add_wire(clbit) - - def add_qreg(self, qreg): - """Add all wires in a quantum register.""" - if not isinstance(qreg, QuantumRegister): - raise DAGCircuitError("not a QuantumRegister instance.") - if qreg.name in self.qregs: - raise DAGCircuitError(f"duplicate register {qreg.name}") - self.qregs[qreg.name] = qreg - existing_qubits = set(self.qubits) - for j in range(qreg.size): - if qreg[j] in self._qubit_indices: - self._qubit_indices[qreg[j]].registers.append((qreg, j)) - if qreg[j] not in existing_qubits: - self.qubits.append(qreg[j]) - self._qubit_indices[qreg[j]] = BitLocations( - len(self.qubits) - 1, registers=[(qreg, j)] - ) - self._add_wire(qreg[j]) - - def add_creg(self, creg): - """Add all wires in a classical register.""" - if not isinstance(creg, ClassicalRegister): - raise DAGCircuitError("not a ClassicalRegister instance.") - if creg.name in self.cregs: - raise DAGCircuitError(f"duplicate register {creg.name}") - self.cregs[creg.name] = creg - existing_clbits = set(self.clbits) - for j in range(creg.size): - if creg[j] in self._clbit_indices: - self._clbit_indices[creg[j]].registers.append((creg, j)) - if creg[j] not in existing_clbits: - self.clbits.append(creg[j]) - self._clbit_indices[creg[j]] = BitLocations( - len(self.clbits) - 1, registers=[(creg, j)] - ) - self._add_wire(creg[j]) - - def add_input_var(self, var: expr.Var): - """Add an input variable to the circuit. - - Args: - var: the variable to add.""" - if self._vars_by_type[_DAGVarType.CAPTURE]: - raise DAGCircuitError("cannot add inputs to a circuit with captures") - self._add_var(var, _DAGVarType.INPUT) - - def add_captured_var(self, var: expr.Var): - """Add a captured variable to the circuit. - - Args: - var: the variable to add.""" - if self._vars_by_type[_DAGVarType.INPUT]: - raise DAGCircuitError("cannot add captures to a circuit with inputs") - self._add_var(var, _DAGVarType.CAPTURE) - - def add_declared_var(self, var: expr.Var): - """Add a declared local variable to the circuit. - - Args: - var: the variable to add.""" - self._add_var(var, _DAGVarType.DECLARE) - - def _add_var(self, var: expr.Var, type_: _DAGVarType): - """Inner function to add any variable to the DAG. ``location`` should be a reference one of - the ``self._vars_*`` tracking dictionaries. - """ - # The setup of the initial graph structure between an "in" and an "out" node is the same as - # the bit-related `_add_wire`, but this logically needs to do different bookkeeping around - # tracking the properties. - if not var.standalone: - raise DAGCircuitError( - "cannot add variables that wrap `Clbit` or `ClassicalRegister` instances" - ) - if (previous := self._vars_info.get(var.name, None)) is not None: - if previous.var == var: - raise DAGCircuitError(f"'{var}' is already present in the circuit") - raise DAGCircuitError( - f"cannot add '{var}' as its name shadows the existing '{previous.var}'" - ) - in_node = DAGInNode(wire=var) - out_node = DAGOutNode(wire=var) - in_node._node_id, out_node._node_id = self._multi_graph.add_nodes_from((in_node, out_node)) - self._multi_graph.add_edge(in_node._node_id, out_node._node_id, var) - self.input_map[var] = in_node - self.output_map[var] = out_node - self._vars_by_type[type_].add(var) - self._vars_info[var.name] = _DAGVarInfo(var, type_, in_node, out_node) - - def _add_wire(self, wire): - """Add a qubit or bit to the circuit. - - Args: - wire (Bit): the wire to be added - - This adds a pair of in and out nodes connected by an edge. - - Raises: - DAGCircuitError: if trying to add duplicate wire - """ - if wire not in self._wires: - self._wires.add(wire) - - inp_node = DAGInNode(wire=wire) - outp_node = DAGOutNode(wire=wire) - input_map_id, output_map_id = self._multi_graph.add_nodes_from([inp_node, outp_node]) - inp_node._node_id = input_map_id - outp_node._node_id = output_map_id - self.input_map[wire] = inp_node - self.output_map[wire] = outp_node - self._multi_graph.add_edge(inp_node._node_id, outp_node._node_id, wire) - else: - raise DAGCircuitError(f"duplicate wire {wire}") - - def find_bit(self, bit: Bit) -> BitLocations: - """ - Finds locations in the circuit, by mapping the Qubit and Clbit to positional index - BitLocations is defined as: BitLocations = namedtuple("BitLocations", ("index", "registers")) - - Args: - bit (Bit): The bit to locate. - - Returns: - namedtuple(int, List[Tuple(Register, int)]): A 2-tuple. The first element (``index``) - contains the index at which the ``Bit`` can be found (in either - :obj:`~DAGCircuit.qubits`, :obj:`~DAGCircuit.clbits`, depending on its - type). The second element (``registers``) is a list of ``(register, index)`` - pairs with an entry for each :obj:`~Register` in the circuit which contains the - :obj:`~Bit` (and the index in the :obj:`~Register` at which it can be found). - - Raises: - DAGCircuitError: If the supplied :obj:`~Bit` was of an unknown type. - DAGCircuitError: If the supplied :obj:`~Bit` could not be found on the circuit. - """ - try: - if isinstance(bit, Qubit): - return self._qubit_indices[bit] - elif isinstance(bit, Clbit): - return self._clbit_indices[bit] - else: - raise DAGCircuitError(f"Could not locate bit of unknown type: {type(bit)}") - except KeyError as err: - raise DAGCircuitError( - f"Could not locate provided bit: {bit}. Has it been added to the DAGCircuit?" - ) from err - - def remove_clbits(self, *clbits): - """ - Remove classical bits from the circuit. All bits MUST be idle. - Any registers with references to at least one of the specified bits will - also be removed. - - Args: - clbits (List[Clbit]): The bits to remove. - - Raises: - DAGCircuitError: a clbit is not a :obj:`.Clbit`, is not in the circuit, - or is not idle. - """ - if any(not isinstance(clbit, Clbit) for clbit in clbits): - raise DAGCircuitError( - f"clbits not of type Clbit: {[b for b in clbits if not isinstance(b, Clbit)]}" - ) - - clbits = set(clbits) - unknown_clbits = clbits.difference(self.clbits) - if unknown_clbits: - raise DAGCircuitError(f"clbits not in circuit: {unknown_clbits}") - - busy_clbits = {bit for bit in clbits if not self._is_wire_idle(bit)} - if busy_clbits: - raise DAGCircuitError(f"clbits not idle: {busy_clbits}") - - # remove any references to bits - cregs_to_remove = {creg for creg in self.cregs.values() if not clbits.isdisjoint(creg)} - self.remove_cregs(*cregs_to_remove) - - for clbit in clbits: - self._remove_idle_wire(clbit) - self.clbits.remove(clbit) - del self._clbit_indices[clbit] - - # Update the indices of remaining clbits - for i, clbit in enumerate(self.clbits): - self._clbit_indices[clbit] = self._clbit_indices[clbit]._replace(index=i) - - def remove_cregs(self, *cregs): - """ - Remove classical registers from the circuit, leaving underlying bits - in place. - - Raises: - DAGCircuitError: a creg is not a ClassicalRegister, or is not in - the circuit. - """ - if any(not isinstance(creg, ClassicalRegister) for creg in cregs): - raise DAGCircuitError( - "cregs not of type ClassicalRegister: " - f"{[r for r in cregs if not isinstance(r, ClassicalRegister)]}" - ) - - unknown_cregs = set(cregs).difference(self.cregs.values()) - if unknown_cregs: - raise DAGCircuitError(f"cregs not in circuit: {unknown_cregs}") - - for creg in cregs: - del self.cregs[creg.name] - for j in range(creg.size): - bit = creg[j] - bit_position = self._clbit_indices[bit] - bit_position.registers.remove((creg, j)) - - def remove_qubits(self, *qubits): - """ - Remove quantum bits from the circuit. All bits MUST be idle. - Any registers with references to at least one of the specified bits will - also be removed. - - Args: - qubits (List[~qiskit.circuit.Qubit]): The bits to remove. - - Raises: - DAGCircuitError: a qubit is not a :obj:`~.circuit.Qubit`, is not in the circuit, - or is not idle. - """ - if any(not isinstance(qubit, Qubit) for qubit in qubits): - raise DAGCircuitError( - f"qubits not of type Qubit: {[b for b in qubits if not isinstance(b, Qubit)]}" - ) - - qubits = set(qubits) - unknown_qubits = qubits.difference(self.qubits) - if unknown_qubits: - raise DAGCircuitError(f"qubits not in circuit: {unknown_qubits}") - - busy_qubits = {bit for bit in qubits if not self._is_wire_idle(bit)} - if busy_qubits: - raise DAGCircuitError(f"qubits not idle: {busy_qubits}") - - # remove any references to bits - qregs_to_remove = {qreg for qreg in self.qregs.values() if not qubits.isdisjoint(qreg)} - self.remove_qregs(*qregs_to_remove) - - for qubit in qubits: - self._remove_idle_wire(qubit) - self.qubits.remove(qubit) - del self._qubit_indices[qubit] - - # Update the indices of remaining qubits - for i, qubit in enumerate(self.qubits): - self._qubit_indices[qubit] = self._qubit_indices[qubit]._replace(index=i) - - def remove_qregs(self, *qregs): - """ - Remove quantum registers from the circuit, leaving underlying bits - in place. - - Raises: - DAGCircuitError: a qreg is not a QuantumRegister, or is not in - the circuit. - """ - if any(not isinstance(qreg, QuantumRegister) for qreg in qregs): - raise DAGCircuitError( - f"qregs not of type QuantumRegister: " - f"{[r for r in qregs if not isinstance(r, QuantumRegister)]}" - ) - - unknown_qregs = set(qregs).difference(self.qregs.values()) - if unknown_qregs: - raise DAGCircuitError(f"qregs not in circuit: {unknown_qregs}") - - for qreg in qregs: - del self.qregs[qreg.name] - for j in range(qreg.size): - bit = qreg[j] - bit_position = self._qubit_indices[bit] - bit_position.registers.remove((qreg, j)) - - def _is_wire_idle(self, wire): - """Check if a wire is idle. - - Args: - wire (Bit): a wire in the circuit. - - Returns: - bool: true if the wire is idle, false otherwise. - - Raises: - DAGCircuitError: the wire is not in the circuit. - """ - if wire not in self._wires: - raise DAGCircuitError(f"wire {wire} not in circuit") - - try: - child = next(self.successors(self.input_map[wire])) - except StopIteration as e: - raise DAGCircuitError( - f"Invalid dagcircuit input node {self.input_map[wire]} has no output" - ) from e - return child is self.output_map[wire] - - def _remove_idle_wire(self, wire): - """Remove an idle qubit or bit from the circuit. - - Args: - wire (Bit): the wire to be removed, which MUST be idle. - """ - inp_node = self.input_map[wire] - oup_node = self.output_map[wire] - - self._multi_graph.remove_node(inp_node._node_id) - self._multi_graph.remove_node(oup_node._node_id) - self._wires.remove(wire) - del self.input_map[wire] - del self.output_map[wire] - - def _check_condition(self, name, condition): - """Verify that the condition is valid. - - Args: - name (string): used for error reporting - condition (tuple or None): a condition tuple (ClassicalRegister, int) or (Clbit, bool) - - Raises: - DAGCircuitError: if conditioning on an invalid register - """ - if condition is None: - return - resources = condition_resources(condition) - for creg in resources.cregs: - if creg.name not in self.cregs: - raise DAGCircuitError(f"invalid creg in condition for {name}") - if not set(resources.clbits).issubset(self.clbits): - raise DAGCircuitError(f"invalid clbits in condition for {name}") - - def _check_wires(self, args: Iterable[Bit | expr.Var], amap: dict[Bit | expr.Var, Any]): - """Check the values of a list of wire arguments. - - For each element of args, check that amap contains it. - - Args: - args: the elements to be checked - amap: a dictionary keyed on Qubits/Clbits - - Raises: - DAGCircuitError: if a qubit is not contained in amap - """ - # Check for each wire - for wire in args: - if wire not in amap: - raise DAGCircuitError(f"wire {wire} not found in {amap}") - - def _increment_op(self, op_name): - if op_name in self._op_names: - self._op_names[op_name] += 1 - else: - self._op_names[op_name] = 1 - - def _decrement_op(self, op_name): - if self._op_names[op_name] == 1: - del self._op_names[op_name] - else: - self._op_names[op_name] -= 1 - - def copy_empty_like(self, *, vars_mode: _VarsMode = "alike"): - """Return a copy of self with the same structure but empty. - - That structure includes: - * name and other metadata - * global phase - * duration - * all the qubits and clbits, including the registers - * all the classical variables, with a mode defined by ``vars_mode``. - - Args: - vars_mode: The mode to handle realtime variables in. - - alike - The variables in the output DAG will have the same declaration semantics as - in the original circuit. For example, ``input`` variables in the source will be - ``input`` variables in the output DAG. - - captures - All variables will be converted to captured variables. This is useful when you - are building a new layer for an existing DAG that you will want to - :meth:`compose` onto the base, since :meth:`compose` can inline captures onto - the base circuit (but not other variables). - - drop - The output DAG will have no variables defined. - - Returns: - DAGCircuit: An empty copy of self. - """ - target_dag = DAGCircuit() - target_dag.name = self.name - target_dag._global_phase = self._global_phase - target_dag.duration = self.duration - target_dag.unit = self.unit - target_dag.metadata = self.metadata - target_dag._key_cache = self._key_cache - - target_dag.add_qubits(self.qubits) - target_dag.add_clbits(self.clbits) - - for qreg in self.qregs.values(): - target_dag.add_qreg(qreg) - for creg in self.cregs.values(): - target_dag.add_creg(creg) - - if vars_mode == "alike": - for var in self.iter_input_vars(): - target_dag.add_input_var(var) - for var in self.iter_captured_vars(): - target_dag.add_captured_var(var) - for var in self.iter_declared_vars(): - target_dag.add_declared_var(var) - elif vars_mode == "captures": - for var in self.iter_vars(): - target_dag.add_captured_var(var) - elif vars_mode == "drop": - pass - else: # pragma: no cover - raise ValueError(f"unknown vars_mode: '{vars_mode}'") - - return target_dag - - def _apply_op_node_back(self, node: DAGOpNode, *, check: bool = False): - additional = () - if _may_have_additional_wires(node): - # This is the slow path; most of the time, this won't happen. - additional = set(_additional_wires(node.op)).difference(node.cargs) - - if check: - self._check_condition(node.name, node.condition) - self._check_wires(node.qargs, self.output_map) - self._check_wires(node.cargs, self.output_map) - self._check_wires(additional, self.output_map) - - node._node_id = self._multi_graph.add_node(node) - self._increment_op(node.name) - - # Add new in-edges from predecessors of the output nodes to the - # operation node while deleting the old in-edges of the output nodes - # and adding new edges from the operation node to each output node - self._multi_graph.insert_node_on_in_edges_multiple( - node._node_id, - [ - self.output_map[bit]._node_id - for bits in (node.qargs, node.cargs, additional) - for bit in bits - ], - ) - return node - - def apply_operation_back( - self, - op: Operation, - qargs: Iterable[Qubit] = (), - cargs: Iterable[Clbit] = (), - *, - check: bool = True, - ) -> DAGOpNode: - """Apply an operation to the output of the circuit. - - Args: - op (qiskit.circuit.Operation): the operation associated with the DAG node - qargs (tuple[~qiskit.circuit.Qubit]): qubits that op will be applied to - cargs (tuple[Clbit]): cbits that op will be applied to - check (bool): If ``True`` (default), this function will enforce that the - :class:`.DAGCircuit` data-structure invariants are maintained (all ``qargs`` are - :class:`~.circuit.Qubit`\\ s, all are in the DAG, etc). If ``False``, the caller *must* - uphold these invariants itself, but the cost of several checks will be skipped. - This is most useful when building a new DAG from a source of known-good nodes. - Returns: - DAGOpNode: the node for the op that was added to the dag - - Raises: - DAGCircuitError: if a leaf node is connected to multiple outputs - - """ - return self._apply_op_node_back( - DAGOpNode(op=op, qargs=tuple(qargs), cargs=tuple(cargs), dag=self), check=check - ) - - def apply_operation_front( - self, - op: Operation, - qargs: Sequence[Qubit] = (), - cargs: Sequence[Clbit] = (), - *, - check: bool = True, - ) -> DAGOpNode: - """Apply an operation to the input of the circuit. - - Args: - op (qiskit.circuit.Operation): the operation associated with the DAG node - qargs (tuple[~qiskit.circuit.Qubit]): qubits that op will be applied to - cargs (tuple[Clbit]): cbits that op will be applied to - check (bool): If ``True`` (default), this function will enforce that the - :class:`.DAGCircuit` data-structure invariants are maintained (all ``qargs`` are - :class:`~.circuit.Qubit`\\ s, all are in the DAG, etc). If ``False``, the caller *must* - uphold these invariants itself, but the cost of several checks will be skipped. - This is most useful when building a new DAG from a source of known-good nodes. - Returns: - DAGOpNode: the node for the op that was added to the dag - - Raises: - DAGCircuitError: if initial nodes connected to multiple out edges - """ - qargs = tuple(qargs) - cargs = tuple(cargs) - additional = () - - node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self) - if _may_have_additional_wires(node): - # This is the slow path; most of the time, this won't happen. - additional = set(_additional_wires(node.op)).difference(cargs) - - if check: - self._check_condition(node.name, node.condition) - self._check_wires(node.qargs, self.output_map) - self._check_wires(node.cargs, self.output_map) - self._check_wires(additional, self.output_map) - - node._node_id = self._multi_graph.add_node(node) - self._increment_op(node.name) - - # Add new out-edges to successors of the input nodes from the - # operation node while deleting the old out-edges of the input nodes - # and adding new edges to the operation node from each input node - self._multi_graph.insert_node_on_out_edges_multiple( - node._node_id, - [ - self.input_map[bit]._node_id - for bits in (node.qargs, node.cargs, additional) - for bit in bits - ], - ) - return node - - def compose( - self, other, qubits=None, clbits=None, front=False, inplace=True, *, inline_captures=False - ): - """Compose the ``other`` circuit onto the output of this circuit. - - A subset of input wires of ``other`` are mapped - to a subset of output wires of this circuit. - - ``other`` can be narrower or of equal width to ``self``. - - Args: - other (DAGCircuit): circuit to compose with self - qubits (list[~qiskit.circuit.Qubit|int]): qubits of self to compose onto. - clbits (list[Clbit|int]): clbits of self to compose onto. - front (bool): If True, front composition will be performed (not implemented yet) - inplace (bool): If True, modify the object. Otherwise return composed circuit. - inline_captures (bool): If ``True``, variables marked as "captures" in the ``other`` DAG - will inlined onto existing uses of those same variables in ``self``. If ``False``, - all variables in ``other`` are required to be distinct from ``self``, and they will - be added to ``self``. - - .. - Note: unlike `QuantumCircuit.compose`, there's no `var_remap` argument here. That's - because the `DAGCircuit` inner-block structure isn't set up well to allow the recursion, - and `DAGCircuit.compose` is generally only used to rebuild a DAG from layers within - itself than to join unrelated circuits. While there's no strong motivating use-case - (unlike the `QuantumCircuit` equivalent), it's safer and more performant to not provide - the option. - - Returns: - DAGCircuit: the composed dag (returns None if inplace==True). - - Raises: - DAGCircuitError: if ``other`` is wider or there are duplicate edge mappings. - """ - if front: - raise DAGCircuitError("Front composition not supported yet.") - - if len(other.qubits) > len(self.qubits) or len(other.clbits) > len(self.clbits): - raise DAGCircuitError( - "Trying to compose with another DAGCircuit which has more 'in' edges." - ) - - # number of qubits and clbits must match number in circuit or None - identity_qubit_map = dict(zip(other.qubits, self.qubits)) - identity_clbit_map = dict(zip(other.clbits, self.clbits)) - if qubits is None: - qubit_map = identity_qubit_map - elif len(qubits) != len(other.qubits): - raise DAGCircuitError( - "Number of items in qubits parameter does not" - " match number of qubits in the circuit." - ) - else: - qubit_map = { - other.qubits[i]: (self.qubits[q] if isinstance(q, int) else q) - for i, q in enumerate(qubits) - } - if clbits is None: - clbit_map = identity_clbit_map - elif len(clbits) != len(other.clbits): - raise DAGCircuitError( - "Number of items in clbits parameter does not" - " match number of clbits in the circuit." - ) - else: - clbit_map = { - other.clbits[i]: (self.clbits[c] if isinstance(c, int) else c) - for i, c in enumerate(clbits) - } - edge_map = {**qubit_map, **clbit_map} or None - - # if no edge_map, try to do a 1-1 mapping in order - if edge_map is None: - edge_map = {**identity_qubit_map, **identity_clbit_map} - - # Check the edge_map for duplicate values - if len(set(edge_map.values())) != len(edge_map): - raise DAGCircuitError("duplicates in wire_map") - - # Compose - if inplace: - dag = self - else: - dag = copy.deepcopy(self) - dag.global_phase += other.global_phase - - for gate, cals in other.calibrations.items(): - dag._calibrations[gate].update(cals) - - # This is all the handling we need for realtime variables, if there's no remapping. They: - # - # * get added to the DAG and then operations involving them get appended on normally. - # * get inlined onto an existing variable, then operations get appended normally. - # * there's a clash or a failed inlining, and we just raise an error. - # - # Notably if there's no remapping, there's no need to recurse into control-flow or to do any - # Var rewriting during the Expr visits. - for var in other.iter_input_vars(): - dag.add_input_var(var) - if inline_captures: - for var in other.iter_captured_vars(): - if not dag.has_var(var): - raise DAGCircuitError( - f"Variable '{var}' to be inlined is not in the base DAG." - " If you wanted it to be automatically added, use `inline_captures=False`." - ) - else: - for var in other.iter_captured_vars(): - dag.add_captured_var(var) - for var in other.iter_declared_vars(): - dag.add_declared_var(var) - - # Ensure that the error raised here is a `DAGCircuitError` for backwards compatibility. - def _reject_new_register(reg): - raise DAGCircuitError(f"No register with '{reg.bits}' to map this expression onto.") - - variable_mapper = _classical_resource_map.VariableMapper( - dag.cregs.values(), edge_map, add_register=_reject_new_register - ) - for nd in other.topological_nodes(): - if isinstance(nd, DAGInNode): - if isinstance(nd.wire, Bit): - # if in edge_map, get new name, else use existing name - m_wire = edge_map.get(nd.wire, nd.wire) - # the mapped wire should already exist - if m_wire not in dag.output_map: - raise DAGCircuitError( - f"wire {m_wire.register.name}[{m_wire.index}] not in self" - ) - if nd.wire not in other._wires: - raise DAGCircuitError( - f"inconsistent wire type for {nd.register.name}[{nd.wire.index}] in other" - ) - # If it's a Var wire, we already checked that it exists in the destination. - elif isinstance(nd, DAGOutNode): - # ignore output nodes - pass - elif isinstance(nd, DAGOpNode): - m_qargs = [edge_map.get(x, x) for x in nd.qargs] - m_cargs = [edge_map.get(x, x) for x in nd.cargs] - inst = nd._to_circuit_instruction(deepcopy=True) - m_op = None - if inst.condition is not None: - if inst.is_control_flow(): - m_op = inst.operation - m_op.condition = variable_mapper.map_condition( - inst.condition, allow_reorder=True - ) - else: - m_op = inst.operation.c_if( - *variable_mapper.map_condition(inst.condition, allow_reorder=True) - ) - elif inst.is_control_flow() and isinstance(inst.operation, SwitchCaseOp): - m_op = inst.operation - m_op.target = variable_mapper.map_target(m_op.target) - if m_op is None: - inst = inst.replace(qubits=m_qargs, clbits=m_cargs) - else: - inst = inst.replace(operation=m_op, qubits=m_qargs, clbits=m_cargs) - dag._apply_op_node_back(DAGOpNode.from_instruction(inst), check=False) - else: - raise DAGCircuitError(f"bad node type {type(nd)}") - - if not inplace: - return dag - else: - return None - - def reverse_ops(self): - """Reverse the operations in the ``self`` circuit. - - Returns: - DAGCircuit: the reversed dag. - """ - # TODO: speed up - # pylint: disable=cyclic-import - from qiskit.converters import dag_to_circuit, circuit_to_dag - - qc = dag_to_circuit(self) - reversed_qc = qc.reverse_ops() - reversed_dag = circuit_to_dag(reversed_qc) - return reversed_dag - - def idle_wires(self, ignore=None): - """Return idle wires. - - Args: - ignore (list(str)): List of node names to ignore. Default: [] - - Yields: - Bit: Bit in idle wire. - - Raises: - DAGCircuitError: If the DAG is invalid - """ - if ignore is None: - ignore = set() - ignore_set = set(ignore) - for wire in self._wires: - if not ignore: - if self._is_wire_idle(wire): - yield wire - else: - for node in self.nodes_on_wire(wire, only_ops=True): - if node.op.name not in ignore_set: - # If we found an op node outside of ignore we can stop iterating over the wire - break - else: - yield wire - - def size(self, *, recurse: bool = False): - """Return the number of operations. If there is control flow present, this count may only - be an estimate, as the complete control-flow path cannot be statically known. - - Args: - recurse: if ``True``, then recurse into control-flow operations. For loops with - known-length iterators are counted unrolled. If-else blocks sum both of the two - branches. While loops are counted as if the loop body runs once only. Defaults to - ``False`` and raises :class:`.DAGCircuitError` if any control flow is present, to - avoid silently returning a mostly meaningless number. - - Returns: - int: the circuit size - - Raises: - DAGCircuitError: if an unknown :class:`.ControlFlowOp` is present in a call with - ``recurse=True``, or any control flow is present in a non-recursive call. - """ - length = len(self._multi_graph) - 2 * len(self._wires) - if not recurse: - if any(x in self._op_names for x in CONTROL_FLOW_OP_NAMES): - raise DAGCircuitError( - "Size with control flow is ambiguous." - " You may use `recurse=True` to get a result," - " but see this method's documentation for the meaning of this." - ) - return length - # pylint: disable=cyclic-import - from qiskit.converters import circuit_to_dag - - for node in self.op_nodes(ControlFlowOp): - if isinstance(node.op, ForLoopOp): - indexset = node.op.params[0] - inner = len(indexset) * circuit_to_dag(node.op.blocks[0]).size(recurse=True) - elif isinstance(node.op, WhileLoopOp): - inner = circuit_to_dag(node.op.blocks[0]).size(recurse=True) - elif isinstance(node.op, (IfElseOp, SwitchCaseOp)): - inner = sum(circuit_to_dag(block).size(recurse=True) for block in node.op.blocks) - else: - raise DAGCircuitError(f"unknown control-flow type: '{node.op.name}'") - # Replace the "1" for the node itself with the actual count. - length += inner - 1 - return length - - def depth(self, *, recurse: bool = False): - """Return the circuit depth. If there is control flow present, this count may only be an - estimate, as the complete control-flow path cannot be statically known. - - Args: - recurse: if ``True``, then recurse into control-flow operations. For loops - with known-length iterators are counted as if the loop had been manually unrolled - (*i.e.* with each iteration of the loop body written out explicitly). - If-else blocks take the longer case of the two branches. While loops are counted as - if the loop body runs once only. Defaults to ``False`` and raises - :class:`.DAGCircuitError` if any control flow is present, to avoid silently - returning a nonsensical number. - - Returns: - int: the circuit depth - - Raises: - DAGCircuitError: if not a directed acyclic graph - DAGCircuitError: if unknown control flow is present in a recursive call, or any control - flow is present in a non-recursive call. - """ - if recurse: - from qiskit.converters import circuit_to_dag # pylint: disable=cyclic-import - - node_lookup = {} - for node in self.op_nodes(ControlFlowOp): - weight = len(node.op.params[0]) if isinstance(node.op, ForLoopOp) else 1 - if weight == 0: - node_lookup[node._node_id] = 0 - else: - node_lookup[node._node_id] = weight * max( - circuit_to_dag(block).depth(recurse=True) for block in node.op.blocks - ) - - def weight_fn(_source, target, _edge): - return node_lookup.get(target, 1) - - else: - if any(x in self._op_names for x in CONTROL_FLOW_OP_NAMES): - raise DAGCircuitError( - "Depth with control flow is ambiguous." - " You may use `recurse=True` to get a result," - " but see this method's documentation for the meaning of this." - ) - weight_fn = None - - try: - depth = rx.dag_longest_path_length(self._multi_graph, weight_fn) - 1 - except rx.DAGHasCycle as ex: - raise DAGCircuitError("not a DAG") from ex - return depth if depth >= 0 else 0 - - def width(self): - """Return the total number of qubits + clbits used by the circuit. - This function formerly returned the number of qubits by the calculation - return len(self._wires) - self.num_clbits() - but was changed by issue #2564 to return number of qubits + clbits - with the new function DAGCircuit.num_qubits replacing the former - semantic of DAGCircuit.width(). - """ - return len(self._wires) - - def num_qubits(self): - """Return the total number of qubits used by the circuit. - num_qubits() replaces former use of width(). - DAGCircuit.width() now returns qubits + clbits for - consistency with Circuit.width() [qiskit-terra #2564]. - """ - return len(self.qubits) - - def num_clbits(self): - """Return the total number of classical bits used by the circuit.""" - return len(self.clbits) - - def num_tensor_factors(self): - """Compute how many components the circuit can decompose into.""" - return rx.number_weakly_connected_components(self._multi_graph) - - @property - def num_vars(self): - """Total number of classical variables tracked by the circuit.""" - return len(self._vars_info) - - @property - def num_input_vars(self): - """Number of input classical variables tracked by the circuit.""" - return len(self._vars_by_type[_DAGVarType.INPUT]) - - @property - def num_captured_vars(self): - """Number of captured classical variables tracked by the circuit.""" - return len(self._vars_by_type[_DAGVarType.CAPTURE]) - - @property - def num_declared_vars(self): - """Number of declared local classical variables tracked by the circuit.""" - return len(self._vars_by_type[_DAGVarType.DECLARE]) - - def iter_vars(self): - """Iterable over all the classical variables tracked by the circuit.""" - return itertools.chain.from_iterable(self._vars_by_type.values()) - - def iter_input_vars(self): - """Iterable over the input classical variables tracked by the circuit.""" - return iter(self._vars_by_type[_DAGVarType.INPUT]) - - def iter_captured_vars(self): - """Iterable over the captured classical variables tracked by the circuit.""" - return iter(self._vars_by_type[_DAGVarType.CAPTURE]) - - def iter_declared_vars(self): - """Iterable over the declared local classical variables tracked by the circuit.""" - return iter(self._vars_by_type[_DAGVarType.DECLARE]) - - def has_var(self, var: str | expr.Var) -> bool: - """Is this realtime variable in the DAG? - - Args: - var: the variable or name to check. - """ - if isinstance(var, str): - return var in self._vars_info - return (info := self._vars_info.get(var.name, False)) and info.var is var - - def __eq__(self, other): - # Try to convert to float, but in case of unbound ParameterExpressions - # a TypeError will be raise, fallback to normal equality in those - # cases - try: - self_phase = float(self.global_phase) - other_phase = float(other.global_phase) - if ( - abs((self_phase - other_phase + np.pi) % (2 * np.pi) - np.pi) > 1.0e-10 - ): # TODO: atol? - return False - except TypeError: - if self.global_phase != other.global_phase: - return False - if self.calibrations != other.calibrations: - return False - - # We don't do any semantic equivalence between Var nodes, as things stand; DAGs can only be - # equal in our mind if they use the exact same UUID vars. - if self._vars_by_type != other._vars_by_type: - return False - - self_bit_indices = {bit: idx for idx, bit in enumerate(self.qubits + self.clbits)} - other_bit_indices = {bit: idx for idx, bit in enumerate(other.qubits + other.clbits)} - - self_qreg_indices = { - regname: [self_bit_indices[bit] for bit in reg] for regname, reg in self.qregs.items() - } - self_creg_indices = { - regname: [self_bit_indices[bit] for bit in reg] for regname, reg in self.cregs.items() - } - - other_qreg_indices = { - regname: [other_bit_indices[bit] for bit in reg] for regname, reg in other.qregs.items() - } - other_creg_indices = { - regname: [other_bit_indices[bit] for bit in reg] for regname, reg in other.cregs.items() - } - if self_qreg_indices != other_qreg_indices or self_creg_indices != other_creg_indices: - return False - - def node_eq(node_self, node_other): - return DAGNode.semantic_eq(node_self, node_other, self_bit_indices, other_bit_indices) - - return rx.is_isomorphic_node_match(self._multi_graph, other._multi_graph, node_eq) - - def topological_nodes(self, key=None): - """ - Yield nodes in topological order. - - Args: - key (Callable): A callable which will take a DAGNode object and - return a string sort key. If not specified the - :attr:`~qiskit.dagcircuit.DAGNode.sort_key` attribute will be - used as the sort key for each node. - - Returns: - generator(DAGOpNode, DAGInNode, or DAGOutNode): node in topological order - """ - - def _key(x): - return x.sort_key - - if key is None: - key = _key - - return iter(rx.lexicographical_topological_sort(self._multi_graph, key=key)) - - def topological_op_nodes(self, key: Callable | None = None) -> Generator[DAGOpNode, Any, Any]: - """ - Yield op nodes in topological order. - - Allowed to pass in specific key to break ties in top order - - Args: - key (Callable): A callable which will take a DAGNode object and - return a string sort key. If not specified the - :attr:`~qiskit.dagcircuit.DAGNode.sort_key` attribute will be - used as the sort key for each node. - - Returns: - generator(DAGOpNode): op node in topological order - """ - return (nd for nd in self.topological_nodes(key) if isinstance(nd, DAGOpNode)) - - def replace_block_with_op( - self, node_block: list[DAGOpNode], op: Operation, wire_pos_map, cycle_check=True - ): - """Replace a block of nodes with a single node. - - This is used to consolidate a block of DAGOpNodes into a single - operation. A typical example is a block of gates being consolidated - into a single ``UnitaryGate`` representing the unitary matrix of the - block. - - Args: - node_block (List[DAGNode]): A list of dag nodes that represents the - node block to be replaced - op (qiskit.circuit.Operation): The operation to replace the - block with - wire_pos_map (Dict[Bit, int]): The dictionary mapping the bits to their positions in the - output ``qargs`` or ``cargs``. This is necessary to reconstruct the arg order over - multiple gates in the combined single op node. If a :class:`.Bit` is not in the - dictionary, it will not be added to the args; this can be useful when dealing with - control-flow operations that have inherent bits in their ``condition`` or ``target`` - fields. :class:`.expr.Var` wires similarly do not need to be in this map, since - they will never be in ``qargs`` or ``cargs``. - cycle_check (bool): When set to True this method will check that - replacing the provided ``node_block`` with a single node - would introduce a cycle (which would invalidate the - ``DAGCircuit``) and will raise a ``DAGCircuitError`` if a cycle - would be introduced. This checking comes with a run time - penalty. If you can guarantee that your input ``node_block`` is - a contiguous block and won't introduce a cycle when it's - contracted to a single node, this can be set to ``False`` to - improve the runtime performance of this method. - - Raises: - DAGCircuitError: if ``cycle_check`` is set to ``True`` and replacing - the specified block introduces a cycle or if ``node_block`` is - empty. - - Returns: - DAGOpNode: The op node that replaces the block. - """ - block_qargs = set() - block_cargs = set() - block_ids = [x._node_id for x in node_block] - - # If node block is empty return early - if not node_block: - raise DAGCircuitError("Can't replace an empty node_block") - - for nd in node_block: - block_qargs |= set(nd.qargs) - block_cargs |= set(nd.cargs) - if (condition := getattr(nd, "condition", None)) is not None: - block_cargs.update(condition_resources(condition).clbits) - elif nd.name in CONTROL_FLOW_OP_NAMES and isinstance(nd.op, SwitchCaseOp): - if isinstance(nd.op.target, Clbit): - block_cargs.add(nd.op.target) - elif isinstance(nd.op.target, ClassicalRegister): - block_cargs.update(nd.op.target) - else: - block_cargs.update(node_resources(nd.op.target).clbits) - - block_qargs = [bit for bit in block_qargs if bit in wire_pos_map] - block_qargs.sort(key=wire_pos_map.get) - block_cargs = [bit for bit in block_cargs if bit in wire_pos_map] - block_cargs.sort(key=wire_pos_map.get) - new_node = DAGOpNode(op, block_qargs, block_cargs, dag=self) - - # check the op to insert matches the number of qubits we put it on - if op.num_qubits != len(block_qargs): - raise DAGCircuitError( - f"Number of qubits in the replacement operation ({op.num_qubits}) is not equal to " - f"the number of qubits in the block ({len(block_qargs)})!" - ) - - try: - new_node._node_id = self._multi_graph.contract_nodes( - block_ids, new_node, check_cycle=cycle_check - ) - except rx.DAGWouldCycle as ex: - raise DAGCircuitError( - "Replacing the specified node block would introduce a cycle" - ) from ex - - self._increment_op(op.name) - - for nd in node_block: - self._decrement_op(nd.name) - - return new_node - - def substitute_node_with_dag(self, node, input_dag, wires=None, propagate_condition=True): - """Replace one node with dag. - - Args: - node (DAGOpNode): node to substitute - input_dag (DAGCircuit): circuit that will substitute the node. - wires (list[Bit] | Dict[Bit, Bit]): gives an order for (qu)bits - in the input circuit. If a list, then the bits refer to those in the ``input_dag``, - and the order gets matched to the node wires by qargs first, then cargs, then - conditions. If a dictionary, then a mapping of bits in the ``input_dag`` to those - that the ``node`` acts on. - - Standalone :class:`~.expr.Var` nodes cannot currently be remapped as part of the - substitution; the ``input_dag`` should be defined over the correct set of variables - already. - - .. - The rule about not remapping `Var`s is to avoid performance pitfalls and reduce - complexity; the creator of the input DAG should easily be able to arrange for - the correct `Var`s to be used, and doing so avoids us needing to recurse through - control-flow operations to do deep remappings. - propagate_condition (bool): If ``True`` (default), then any ``condition`` attribute on - the operation within ``node`` is propagated to each node in the ``input_dag``. If - ``False``, then the ``input_dag`` is assumed to faithfully implement suitable - conditional logic already. This is ignored for :class:`.ControlFlowOp`\\ s (i.e. - treated as if it is ``False``); replacements of those must already fulfill the same - conditional logic or this function would be close to useless for them. - - Returns: - dict: maps node IDs from `input_dag` to their new node incarnations in `self`. - - Raises: - DAGCircuitError: if met with unexpected predecessor/successors - """ - if not isinstance(node, DAGOpNode): - raise DAGCircuitError(f"expected node DAGOpNode, got {type(node)}") - - if isinstance(wires, dict): - wire_map = wires - else: - wires = input_dag.wires if wires is None else wires - node_cargs = set(node.cargs) - node_wire_order = list(node.qargs) + list(node.cargs) - # If we're not propagating it, the number of wires in the input DAG should include the - # condition as well. - if not propagate_condition and _may_have_additional_wires(node): - node_wire_order += [ - wire for wire in _additional_wires(node.op) if wire not in node_cargs - ] - if len(wires) != len(node_wire_order): - raise DAGCircuitError( - f"bit mapping invalid: expected {len(node_wire_order)}, got {len(wires)}" - ) - wire_map = dict(zip(wires, node_wire_order)) - if len(wire_map) != len(node_wire_order): - raise DAGCircuitError("bit mapping invalid: some bits have duplicate entries") - for input_dag_wire, our_wire in wire_map.items(): - if our_wire not in self.input_map: - raise DAGCircuitError(f"bit mapping invalid: {our_wire} is not in this DAG") - if isinstance(our_wire, expr.Var) or isinstance(input_dag_wire, expr.Var): - raise DAGCircuitError("`Var` nodes cannot be remapped during substitution") - # Support mapping indiscriminately between Qubit and AncillaQubit, etc. - check_type = Qubit if isinstance(our_wire, Qubit) else Clbit - if not isinstance(input_dag_wire, check_type): - raise DAGCircuitError( - f"bit mapping invalid: {input_dag_wire} and {our_wire} are different bit types" - ) - if _may_have_additional_wires(node): - node_vars = {var for var in _additional_wires(node.op) if isinstance(var, expr.Var)} - else: - node_vars = set() - dag_vars = set(input_dag.iter_vars()) - if dag_vars - node_vars: - raise DAGCircuitError( - "Cannot replace a node with a DAG with more variables." - f" Variables in node: {node_vars}." - f" Variables in DAG: {dag_vars}." - ) - for var in dag_vars: - wire_map[var] = var - - reverse_wire_map = {b: a for a, b in wire_map.items()} - # It doesn't make sense to try and propagate a condition from a control-flow op; a - # replacement for the control-flow op should implement the operation completely. - if propagate_condition and not node.is_control_flow() and node.condition is not None: - in_dag = input_dag.copy_empty_like() - # The remapping of `condition` below is still using the old code that assumes a 2-tuple. - # This is because this remapping code only makes sense in the case of non-control-flow - # operations being replaced. These can only have the 2-tuple conditions, and the - # ability to set a condition at an individual node level will be deprecated and removed - # in favour of the new-style conditional blocks. The extra logic in here to add - # additional wires into the map as necessary would hugely complicate matters if we tried - # to abstract it out into the `VariableMapper` used elsewhere. - target, value = node.condition - if isinstance(target, Clbit): - new_target = reverse_wire_map.get(target, Clbit()) - if new_target not in wire_map: - in_dag.add_clbits([new_target]) - wire_map[new_target], reverse_wire_map[target] = target, new_target - target_cargs = {new_target} - else: # ClassicalRegister - mapped_bits = [reverse_wire_map.get(bit, Clbit()) for bit in target] - for ours, theirs in zip(target, mapped_bits): - # Update to any new dummy bits we just created to the wire maps. - wire_map[theirs], reverse_wire_map[ours] = ours, theirs - new_target = ClassicalRegister(bits=mapped_bits) - in_dag.add_creg(new_target) - target_cargs = set(new_target) - new_condition = (new_target, value) - for in_node in input_dag.topological_op_nodes(): - if getattr(in_node.op, "condition", None) is not None: - raise DAGCircuitError( - "cannot propagate a condition to an element that already has one" - ) - if target_cargs.intersection(in_node.cargs): - # This is for backwards compatibility with early versions of the method, as it is - # a tested part of the API. In the newer model of a condition being an integral - # part of the operation (not a separate property to be copied over), this error - # is overzealous, because it forbids a custom instruction from implementing the - # condition within its definition rather than at the top level. - raise DAGCircuitError( - "cannot propagate a condition to an element that acts on those bits" - ) - new_op = copy.copy(in_node.op) - if new_condition: - if not isinstance(new_op, ControlFlowOp): - new_op = new_op.c_if(*new_condition) - else: - new_op.condition = new_condition - in_dag.apply_operation_back(new_op, in_node.qargs, in_node.cargs, check=False) - else: - in_dag = input_dag - - if in_dag.global_phase: - self.global_phase += in_dag.global_phase - - # Add wire from pred to succ if no ops on mapped wire on ``in_dag`` - # rustworkx's substitute_node_with_subgraph lacks the DAGCircuit - # context to know what to do in this case (the method won't even see - # these nodes because they're filtered) so we manually retain the - # edges prior to calling substitute_node_with_subgraph and set the - # edge_map_fn callback kwarg to skip these edges when they're - # encountered. - for in_dag_wire, self_wire in wire_map.items(): - input_node = in_dag.input_map[in_dag_wire] - output_node = in_dag.output_map[in_dag_wire] - if in_dag._multi_graph.has_edge(input_node._node_id, output_node._node_id): - pred = self._multi_graph.find_predecessors_by_edge( - node._node_id, lambda edge, wire=self_wire: edge == wire - )[0] - succ = self._multi_graph.find_successors_by_edge( - node._node_id, lambda edge, wire=self_wire: edge == wire - )[0] - self._multi_graph.add_edge(pred._node_id, succ._node_id, self_wire) - for contracted_var in node_vars - dag_vars: - pred = self._multi_graph.find_predecessors_by_edge( - node._node_id, lambda edge, wire=contracted_var: edge == wire - )[0] - succ = self._multi_graph.find_successors_by_edge( - node._node_id, lambda edge, wire=contracted_var: edge == wire - )[0] - self._multi_graph.add_edge(pred._node_id, succ._node_id, contracted_var) - - # Exclude any nodes from in_dag that are not a DAGOpNode or are on - # wires outside the set specified by the wires kwarg - def filter_fn(node): - if not isinstance(node, DAGOpNode): - return False - for _, _, wire in in_dag.edges(node): - if wire not in wire_map: - return False - return True - - # Map edges into and out of node to the appropriate node from in_dag - def edge_map_fn(source, _target, self_wire): - wire = reverse_wire_map[self_wire] - # successor edge - if source == node._node_id: - wire_output_id = in_dag.output_map[wire]._node_id - out_index = in_dag._multi_graph.predecessor_indices(wire_output_id)[0] - # Edge directly from from input nodes to output nodes in in_dag are - # already handled prior to calling rustworkx. Don't map these edges - # in rustworkx. - if not isinstance(in_dag._multi_graph[out_index], DAGOpNode): - return None - # predecessor edge - else: - wire_input_id = in_dag.input_map[wire]._node_id - out_index = in_dag._multi_graph.successor_indices(wire_input_id)[0] - # Edge directly from from input nodes to output nodes in in_dag are - # already handled prior to calling rustworkx. Don't map these edges - # in rustworkx. - if not isinstance(in_dag._multi_graph[out_index], DAGOpNode): - return None - return out_index - - # Adjust edge weights from in_dag - def edge_weight_map(wire): - return wire_map[wire] - - node_map = self._multi_graph.substitute_node_with_subgraph( - node._node_id, in_dag._multi_graph, edge_map_fn, filter_fn, edge_weight_map - ) - self._decrement_op(node.name) - - variable_mapper = _classical_resource_map.VariableMapper( - self.cregs.values(), wire_map, add_register=self.add_creg - ) - # Iterate over nodes of input_circuit and update wires in node objects migrated - # from in_dag - for old_node_index, new_node_index in node_map.items(): - # update node attributes - old_node = in_dag._multi_graph[old_node_index] - m_op = None - if not old_node.is_standard_gate() and isinstance(old_node.op, SwitchCaseOp): - m_op = SwitchCaseOp( - variable_mapper.map_target(old_node.op.target), - old_node.op.cases_specifier(), - label=old_node.op.label, - ) - elif old_node.condition is not None: - m_op = old_node.op - if old_node.is_control_flow(): - m_op.condition = variable_mapper.map_condition(m_op.condition) - else: - new_condition = variable_mapper.map_condition(m_op.condition) - if new_condition is not None: - m_op = m_op.c_if(*new_condition) - m_qargs = [wire_map[x] for x in old_node.qargs] - m_cargs = [wire_map[x] for x in old_node.cargs] - old_instruction = old_node._to_circuit_instruction() - if m_op is None: - new_instruction = old_instruction.replace(qubits=m_qargs, clbits=m_cargs) - else: - new_instruction = old_instruction.replace( - operation=m_op, qubits=m_qargs, clbits=m_cargs - ) - new_node = DAGOpNode.from_instruction(new_instruction) - new_node._node_id = new_node_index - self._multi_graph[new_node_index] = new_node - self._increment_op(new_node.name) - - return {k: self._multi_graph[v] for k, v in node_map.items()} - - def substitute_node(self, node: DAGOpNode, op, inplace: bool = False, propagate_condition=True): - """Replace an DAGOpNode with a single operation. qargs, cargs and - conditions for the new operation will be inferred from the node to be - replaced. The new operation will be checked to match the shape of the - replaced operation. - - Args: - node (DAGOpNode): Node to be replaced - op (qiskit.circuit.Operation): The :class:`qiskit.circuit.Operation` - instance to be added to the DAG - inplace (bool): Optional, default False. If True, existing DAG node - will be modified to include op. Otherwise, a new DAG node will - be used. - propagate_condition (bool): Optional, default True. If True, a condition on the - ``node`` to be replaced will be applied to the new ``op``. This is the legacy - behavior. If either node is a control-flow operation, this will be ignored. If - the ``op`` already has a condition, :exc:`.DAGCircuitError` is raised. - - Returns: - DAGOpNode: the new node containing the added operation. - - Raises: - DAGCircuitError: If replacement operation was incompatible with - location of target node. - """ - - if not isinstance(node, DAGOpNode): - raise DAGCircuitError("Only DAGOpNodes can be replaced.") - - if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits: - raise DAGCircuitError( - f"Cannot replace node of width ({node.op.num_qubits} qubits, " - f"{node.op.num_clbits} clbits) with " - f"operation of mismatched width ({op.num_qubits} qubits, " - f"{op.num_clbits} clbits)." - ) - - # This might include wires that are inherent to the node, like in its `condition` or - # `target` fields, so might be wider than `node.op.num_{qu,cl}bits`. - current_wires = {wire for _, _, wire in self.edges(node)} - new_wires = set(node.qargs) | set(node.cargs) | set(_additional_wires(op)) - - if propagate_condition and not ( - isinstance(node.op, ControlFlowOp) or isinstance(op, ControlFlowOp) - ): - if getattr(op, "condition", None) is not None: - raise DAGCircuitError( - "Cannot propagate a condition to an operation that already has one." - ) - if (old_condition := getattr(node.op, "condition", None)) is not None: - if not isinstance(op, Instruction): - raise DAGCircuitError("Cannot add a condition on a generic Operation.") - if not isinstance(node.op, ControlFlowOp): - op = op.c_if(*old_condition) - else: - op.condition = old_condition - new_wires.update(condition_resources(old_condition).clbits) - - if new_wires != current_wires: - # The new wires must be a non-strict subset of the current wires; if they add new wires, - # we'd not know where to cut the existing wire to insert the new dependency. - raise DAGCircuitError( - f"New operation '{op}' does not span the same wires as the old node '{node}'." - f" New wires: {new_wires}, old wires: {current_wires}." - ) - - if inplace: - if op.name != node.op.name: - self._increment_op(op.name) - self._decrement_op(node.name) - node.op = op - return node - - new_node = copy.copy(node) - new_node.op = op - self._multi_graph[node._node_id] = new_node - if op.name != node.name: - self._increment_op(op.name) - self._decrement_op(node.name) - return new_node - - def separable_circuits( - self, remove_idle_qubits: bool = False, *, vars_mode: _VarsMode = "alike" - ) -> list["DAGCircuit"]: - """Decompose the circuit into sets of qubits with no gates connecting them. - - Args: - remove_idle_qubits (bool): Flag denoting whether to remove idle qubits from - the separated circuits. If ``False``, each output circuit will contain the - same number of qubits as ``self``. - vars_mode: how any realtime :class:`~.expr.Var` nodes should be handled in the output - DAGs. See :meth:`copy_empty_like` for details on the modes. - - Returns: - List[DAGCircuit]: The circuits resulting from separating ``self`` into sets - of disconnected qubits - - Each :class:`~.DAGCircuit` instance returned by this method will contain the same number of - clbits as ``self``. The global phase information in ``self`` will not be maintained - in the subcircuits returned by this method. - """ - connected_components = rx.weakly_connected_components(self._multi_graph) - - # Collect each disconnected subgraph - disconnected_subgraphs = [] - for components in connected_components: - disconnected_subgraphs.append(self._multi_graph.subgraph(list(components))) - - # Helper function for ensuring rustworkx nodes are returned in lexicographical, - # topological order - def _key(x): - return x.sort_key - - # Create new DAGCircuit objects from each of the rustworkx subgraph objects - decomposed_dags = [] - for subgraph in disconnected_subgraphs: - new_dag = self.copy_empty_like(vars_mode=vars_mode) - new_dag.global_phase = 0 - subgraph_is_classical = True - for node in rx.lexicographical_topological_sort(subgraph, key=_key): - if isinstance(node, DAGInNode): - if isinstance(node.wire, Qubit): - subgraph_is_classical = False - if not isinstance(node, DAGOpNode): - continue - new_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False) - - # Ignore DAGs created for empty clbits - if not subgraph_is_classical: - decomposed_dags.append(new_dag) - - if remove_idle_qubits: - for dag in decomposed_dags: - dag.remove_qubits(*(bit for bit in dag.idle_wires() if isinstance(bit, Qubit))) - - return decomposed_dags - - def swap_nodes(self, node1, node2): - """Swap connected nodes e.g. due to commutation. - - Args: - node1 (OpNode): predecessor node - node2 (OpNode): successor node - - Raises: - DAGCircuitError: if either node is not an OpNode or nodes are not connected - """ - if not (isinstance(node1, DAGOpNode) and isinstance(node2, DAGOpNode)): - raise DAGCircuitError("nodes to swap are not both DAGOpNodes") - try: - connected_edges = self._multi_graph.get_all_edge_data(node1._node_id, node2._node_id) - except rx.NoEdgeBetweenNodes as no_common_edge: - raise DAGCircuitError("attempt to swap unconnected nodes") from no_common_edge - node1_id = node1._node_id - node2_id = node2._node_id - for edge in connected_edges[::-1]: - edge_find = lambda x, y=edge: x == y - edge_parent = self._multi_graph.find_predecessors_by_edge(node1_id, edge_find)[0] - self._multi_graph.remove_edge(edge_parent._node_id, node1_id) - self._multi_graph.add_edge(edge_parent._node_id, node2_id, edge) - edge_child = self._multi_graph.find_successors_by_edge(node2_id, edge_find)[0] - self._multi_graph.remove_edge(node1_id, node2_id) - self._multi_graph.add_edge(node2_id, node1_id, edge) - self._multi_graph.remove_edge(node2_id, edge_child._node_id) - self._multi_graph.add_edge(node1_id, edge_child._node_id, edge) - - def node(self, node_id): - """Get the node in the dag. - - Args: - node_id(int): Node identifier. - - Returns: - node: the node. - """ - return self._multi_graph[node_id] - - def nodes(self): - """Iterator for node values. - - Yield: - node: the node. - """ - yield from self._multi_graph.nodes() - - def edges(self, nodes=None): - """Iterator for edge values and source and dest node - - This works by returning the output edges from the specified nodes. If - no nodes are specified all edges from the graph are returned. - - Args: - nodes(DAGOpNode, DAGInNode, or DAGOutNode|list(DAGOpNode, DAGInNode, or DAGOutNode): - Either a list of nodes or a single input node. If none is specified, - all edges are returned from the graph. - - Yield: - edge: the edge in the same format as out_edges the tuple - (source node, destination node, edge data) - """ - if nodes is None: - nodes = self._multi_graph.nodes() - - elif isinstance(nodes, (DAGOpNode, DAGInNode, DAGOutNode)): - nodes = [nodes] - for node in nodes: - raw_nodes = self._multi_graph.out_edges(node._node_id) - for source, dest, edge in raw_nodes: - yield (self._multi_graph[source], self._multi_graph[dest], edge) - - def op_nodes(self, op=None, include_directives=True): - """Get the list of "op" nodes in the dag. - - Args: - op (Type): :class:`qiskit.circuit.Operation` subclass op nodes to - return. If None, return all op nodes. - include_directives (bool): include `barrier`, `snapshot` etc. - - Returns: - list[DAGOpNode]: the list of node ids containing the given op. - """ - nodes = [] - filter_is_nonstandard = getattr(op, "_standard_gate", None) is None - for node in self._multi_graph.nodes(): - if isinstance(node, DAGOpNode): - if not include_directives and node.is_directive(): - continue - if op is None or ( - # This middle catch is to avoid Python-space operation creation for most uses of - # `op`; we're usually just looking for control-flow ops, and standard gates - # aren't control-flow ops. - not (filter_is_nonstandard and node.is_standard_gate()) - and isinstance(node.op, op) - ): - nodes.append(node) - return nodes - - def gate_nodes(self): - """Get the list of gate nodes in the dag. - - Returns: - list[DAGOpNode]: the list of DAGOpNodes that represent gates. - """ - nodes = [] - for node in self.op_nodes(): - if isinstance(node.op, Gate): - nodes.append(node) - return nodes - - def named_nodes(self, *names): - """Get the set of "op" nodes with the given name.""" - named_nodes = [] - for node in self._multi_graph.nodes(): - if isinstance(node, DAGOpNode) and node.name in names: - named_nodes.append(node) - return named_nodes - - def two_qubit_ops(self): - """Get list of 2 qubit operations. Ignore directives like snapshot and barrier.""" - ops = [] - for node in self.op_nodes(include_directives=False): - if len(node.qargs) == 2: - ops.append(node) - return ops - - def multi_qubit_ops(self): - """Get list of 3+ qubit operations. Ignore directives like snapshot and barrier.""" - ops = [] - for node in self.op_nodes(include_directives=False): - if len(node.qargs) >= 3: - ops.append(node) - return ops - - def longest_path(self): - """Returns the longest path in the dag as a list of DAGOpNodes, DAGInNodes, and DAGOutNodes.""" - return [self._multi_graph[x] for x in rx.dag_longest_path(self._multi_graph)] - - def successors(self, node): - """Returns iterator of the successors of a node as DAGOpNodes and DAGOutNodes.""" - return iter(self._multi_graph.successors(node._node_id)) - - def predecessors(self, node): - """Returns iterator of the predecessors of a node as DAGOpNodes and DAGInNodes.""" - return iter(self._multi_graph.predecessors(node._node_id)) - - def op_successors(self, node): - """Returns iterator of "op" successors of a node in the dag.""" - return (succ for succ in self.successors(node) if isinstance(succ, DAGOpNode)) - - def op_predecessors(self, node): - """Returns the iterator of "op" predecessors of a node in the dag.""" - return (pred for pred in self.predecessors(node) if isinstance(pred, DAGOpNode)) - - def is_successor(self, node, node_succ): - """Checks if a second node is in the successors of node.""" - return self._multi_graph.has_edge(node._node_id, node_succ._node_id) - - def is_predecessor(self, node, node_pred): - """Checks if a second node is in the predecessors of node.""" - return self._multi_graph.has_edge(node_pred._node_id, node._node_id) - - def quantum_predecessors(self, node): - """Returns iterator of the predecessors of a node that are - connected by a quantum edge as DAGOpNodes and DAGInNodes.""" - return iter( - self._multi_graph.find_predecessors_by_edge( - node._node_id, lambda edge_data: isinstance(edge_data, Qubit) - ) - ) - - def classical_predecessors(self, node): - """Returns iterator of the predecessors of a node that are - connected by a classical edge as DAGOpNodes and DAGInNodes.""" - return iter( - self._multi_graph.find_predecessors_by_edge( - node._node_id, lambda edge_data: not isinstance(edge_data, Qubit) - ) - ) - - def ancestors(self, node): - """Returns set of the ancestors of a node as DAGOpNodes and DAGInNodes.""" - return {self._multi_graph[x] for x in rx.ancestors(self._multi_graph, node._node_id)} - - def descendants(self, node): - """Returns set of the descendants of a node as DAGOpNodes and DAGOutNodes.""" - return {self._multi_graph[x] for x in rx.descendants(self._multi_graph, node._node_id)} - - def bfs_successors(self, node): - """ - Returns an iterator of tuples of (DAGNode, [DAGNodes]) where the DAGNode is the current node - and [DAGNode] is its successors in BFS order. - """ - return iter(rx.bfs_successors(self._multi_graph, node._node_id)) - - def quantum_successors(self, node): - """Returns iterator of the successors of a node that are - connected by a quantum edge as Opnodes and DAGOutNodes.""" - return iter( - self._multi_graph.find_successors_by_edge( - node._node_id, lambda edge_data: isinstance(edge_data, Qubit) - ) - ) - - def classical_successors(self, node): - """Returns iterator of the successors of a node that are - connected by a classical edge as DAGOpNodes and DAGInNodes.""" - return iter( - self._multi_graph.find_successors_by_edge( - node._node_id, lambda edge_data: not isinstance(edge_data, Qubit) - ) - ) - - def remove_op_node(self, node): - """Remove an operation node n. - - Add edges from predecessors to successors. - """ - if not isinstance(node, DAGOpNode): - raise DAGCircuitError( - f'The method remove_op_node only works on DAGOpNodes. A "{type(node)}" ' - "node type was wrongly provided." - ) - - self._multi_graph.remove_node_retain_edges_by_id(node._node_id) - self._decrement_op(node.name) - - def remove_ancestors_of(self, node): - """Remove all of the ancestor operation nodes of node.""" - anc = rx.ancestors(self._multi_graph, node) - # TODO: probably better to do all at once using - # multi_graph.remove_nodes_from; same for related functions ... - - for anc_node in anc: - if isinstance(anc_node, DAGOpNode): - self.remove_op_node(anc_node) - - def remove_descendants_of(self, node): - """Remove all of the descendant operation nodes of node.""" - desc = rx.descendants(self._multi_graph, node) - for desc_node in desc: - if isinstance(desc_node, DAGOpNode): - self.remove_op_node(desc_node) - - def remove_nonancestors_of(self, node): - """Remove all of the non-ancestors operation nodes of node.""" - anc = rx.ancestors(self._multi_graph, node) - comp = list(set(self._multi_graph.nodes()) - set(anc)) - for n in comp: - if isinstance(n, DAGOpNode): - self.remove_op_node(n) - - def remove_nondescendants_of(self, node): - """Remove all of the non-descendants operation nodes of node.""" - dec = rx.descendants(self._multi_graph, node) - comp = list(set(self._multi_graph.nodes()) - set(dec)) - for n in comp: - if isinstance(n, DAGOpNode): - self.remove_op_node(n) - - def front_layer(self): - """Return a list of op nodes in the first layer of this dag.""" - graph_layers = self.multigraph_layers() - try: - next(graph_layers) # Remove input nodes - except StopIteration: - return [] - - op_nodes = [node for node in next(graph_layers) if isinstance(node, DAGOpNode)] - - return op_nodes - - def layers(self, *, vars_mode: _VarsMode = "captures"): - """Yield a shallow view on a layer of this DAGCircuit for all d layers of this circuit. - - A layer is a circuit whose gates act on disjoint qubits, i.e., - a layer has depth 1. The total number of layers equals the - circuit depth d. The layers are indexed from 0 to d-1 with the - earliest layer at index 0. The layers are constructed using a - greedy algorithm. Each returned layer is a dict containing - {"graph": circuit graph, "partition": list of qubit lists}. - - The returned layer contains new (but semantically equivalent) DAGOpNodes, DAGInNodes, - and DAGOutNodes. These are not the same as nodes of the original dag, but are equivalent - via DAGNode.semantic_eq(node1, node2). - - TODO: Gates that use the same cbits will end up in different - layers as this is currently implemented. This may not be - the desired behavior. - - Args: - vars_mode: how any realtime :class:`~.expr.Var` nodes should be handled in the output - DAGs. See :meth:`copy_empty_like` for details on the modes. - """ - graph_layers = self.multigraph_layers() - try: - next(graph_layers) # Remove input nodes - except StopIteration: - return - - for graph_layer in graph_layers: - - # Get the op nodes from the layer, removing any input and output nodes. - op_nodes = [node for node in graph_layer if isinstance(node, DAGOpNode)] - - # Sort to make sure they are in the order they were added to the original DAG - # It has to be done by node_id as graph_layer is just a list of nodes - # with no implied topology - # Drawing tools rely on _node_id to infer order of node creation - # so we need this to be preserved by layers() - op_nodes.sort(key=lambda nd: nd._node_id) - - # Stop yielding once there are no more op_nodes in a layer. - if not op_nodes: - return - - # Construct a shallow copy of self - new_layer = self.copy_empty_like(vars_mode=vars_mode) - - for node in op_nodes: - new_layer._apply_op_node_back(node, check=False) - - # The quantum registers that have an operation in this layer. - support_list = [ - op_node.qargs for op_node in new_layer.op_nodes() if not op_node.is_directive() - ] - - yield {"graph": new_layer, "partition": support_list} - - def serial_layers(self, *, vars_mode: _VarsMode = "captures"): - """Yield a layer for all gates of this circuit. - - A serial layer is a circuit with one gate. The layers have the - same structure as in layers(). - - Args: - vars_mode: how any realtime :class:`~.expr.Var` nodes should be handled in the output - DAGs. See :meth:`copy_empty_like` for details on the modes. - """ - for next_node in self.topological_op_nodes(): - new_layer = self.copy_empty_like(vars_mode=vars_mode) - - # Save the support of the operation we add to the layer - support_list = [] - # Operation data - op = copy.copy(next_node.op) - qargs = copy.copy(next_node.qargs) - cargs = copy.copy(next_node.cargs) - - # Add node to new_layer - new_layer.apply_operation_back(op, qargs, cargs, check=False) - # Add operation to partition - if not getattr(next_node.op, "_directive", False): - support_list.append(list(qargs)) - l_dict = {"graph": new_layer, "partition": support_list} - yield l_dict - - def multigraph_layers(self): - """Yield layers of the multigraph.""" - first_layer = [x._node_id for x in self.input_map.values()] - return iter(rx.layers(self._multi_graph, first_layer)) - - def collect_runs(self, namelist): - """Return a set of non-conditional runs of "op" nodes with the given names. - - For example, "... h q[0]; cx q[0],q[1]; cx q[0],q[1]; h q[1]; .." - would produce the tuple of cx nodes as an element of the set returned - from a call to collect_runs(["cx"]). If instead the cx nodes were - "cx q[0],q[1]; cx q[1],q[0];", the method would still return the - pair in a tuple. The namelist can contain names that are not - in the circuit's basis. - - Nodes must have only one successor to continue the run. - """ - - def filter_fn(node): - return isinstance(node, DAGOpNode) and node.name in namelist and node.condition is None - - group_list = rx.collect_runs(self._multi_graph, filter_fn) - return {tuple(x) for x in group_list} - - def collect_1q_runs(self) -> list[list[DAGOpNode]]: - """Return a set of non-conditional runs of 1q "op" nodes.""" - return rx.collect_runs(self._multi_graph, collect_1q_runs_filter) - - def collect_2q_runs(self): - """Return a set of non-conditional runs of 2q "op" nodes.""" - - def color_fn(edge): - if isinstance(edge, Qubit): - return self.find_bit(edge).index - else: - return None - - return rx.collect_bicolor_runs(self._multi_graph, collect_2q_blocks_filter, color_fn) - - def nodes_on_wire(self, wire, only_ops=False): - """ - Iterator for nodes that affect a given wire. - - Args: - wire (Bit): the wire to be looked at. - only_ops (bool): True if only the ops nodes are wanted; - otherwise, all nodes are returned. - Yield: - Iterator: the successive nodes on the given wire - - Raises: - DAGCircuitError: if the given wire doesn't exist in the DAG - """ - current_node = self.input_map.get(wire, None) - - if not current_node: - raise DAGCircuitError(f"The given wire {str(wire)} is not present in the circuit") - - more_nodes = True - while more_nodes: - more_nodes = False - # allow user to just get ops on the wire - not the input/output nodes - if isinstance(current_node, DAGOpNode) or not only_ops: - yield current_node - - try: - current_node = self._multi_graph.find_adjacent_node_by_edge( - current_node._node_id, lambda x: wire == x - ) - more_nodes = True - except rx.NoSuitableNeighbors: - pass - - def count_ops(self, *, recurse: bool = True): - """Count the occurrences of operation names. - - Args: - recurse: if ``True`` (default), then recurse into control-flow operations. In all - cases, this counts only the number of times the operation appears in any possible - block; both branches of if-elses are counted, and for- and while-loop blocks are - only counted once. - - Returns: - Mapping[str, int]: a mapping of operation names to the number of times it appears. - """ - if not recurse or not CONTROL_FLOW_OP_NAMES.intersection(self._op_names): - return self._op_names.copy() - - # pylint: disable=cyclic-import - from qiskit.converters import circuit_to_dag - - def inner(dag, counts): - for name, count in dag._op_names.items(): - counts[name] += count - for node in dag.op_nodes(ControlFlowOp): - for block in node.op.blocks: - counts = inner(circuit_to_dag(block), counts) - return counts - - return dict(inner(self, defaultdict(int))) - - def count_ops_longest_path(self): - """Count the occurrences of operation names on the longest path. - - Returns a dictionary of counts keyed on the operation name. - """ - op_dict = {} - path = self.longest_path() - path = path[1:-1] # remove qubits at beginning and end of path - for node in path: - name = node.op.name - if name not in op_dict: - op_dict[name] = 1 - else: - op_dict[name] += 1 - return op_dict - - def quantum_causal_cone(self, qubit): - """ - Returns causal cone of a qubit. - - A qubit's causal cone is the set of qubits that can influence the output of that - qubit through interactions, whether through multi-qubit gates or operations. Knowing - the causal cone of a qubit can be useful when debugging faulty circuits, as it can - help identify which wire(s) may be causing the problem. - - This method does not consider any classical data dependency in the ``DAGCircuit``, - classical bit wires are ignored for the purposes of building the causal cone. - - Args: - qubit (~qiskit.circuit.Qubit): The output qubit for which we want to find the causal cone. - - Returns: - Set[~qiskit.circuit.Qubit]: The set of qubits whose interactions affect ``qubit``. - """ - # Retrieve the output node from the qubit - output_node = self.output_map.get(qubit, None) - if not output_node: - raise DAGCircuitError(f"Qubit {qubit} is not part of this circuit.") - - qubits_in_cone = {qubit} - queue = deque(self.quantum_predecessors(output_node)) - - # The processed_non_directive_nodes stores the set of processed non-directive nodes. - # This is an optimization to avoid considering the same non-directive node multiple - # times when reached from different paths. - # The directive nodes (such as barriers or measures) are trickier since when processing - # them we only add their predecessors that intersect qubits_in_cone. Hence, directive - # nodes have to be considered multiple times. - processed_non_directive_nodes = set() - - while queue: - node_to_check = queue.popleft() - - if isinstance(node_to_check, DAGOpNode): - # If the operation is not a directive (in particular not a barrier nor a measure), - # we do not do anything if it was already processed. Otherwise, we add its qubits - # to qubits_in_cone, and append its predecessors to queue. - if not getattr(node_to_check.op, "_directive"): - if node_to_check in processed_non_directive_nodes: - continue - qubits_in_cone = qubits_in_cone.union(set(node_to_check.qargs)) - processed_non_directive_nodes.add(node_to_check) - for pred in self.quantum_predecessors(node_to_check): - if isinstance(pred, DAGOpNode): - queue.append(pred) - else: - # Directives (such as barriers and measures) may be defined over all the qubits, - # yet not all of these qubits should be considered in the causal cone. So we - # only add those predecessors that have qubits in common with qubits_in_cone. - for pred in self.quantum_predecessors(node_to_check): - if isinstance(pred, DAGOpNode) and not qubits_in_cone.isdisjoint( - set(pred.qargs) - ): - queue.append(pred) - - return qubits_in_cone - - def properties(self): - """Return a dictionary of circuit properties.""" - summary = { - "size": self.size(), - "depth": self.depth(), - "width": self.width(), - "qubits": self.num_qubits(), - "bits": self.num_clbits(), - "factors": self.num_tensor_factors(), - "operations": self.count_ops(), - } - return summary - - def draw(self, scale=0.7, filename=None, style="color"): - """ - Draws the dag circuit. - - This function needs `Graphviz `_ to be - installed. Graphviz is not a python package and can't be pip installed - (the ``graphviz`` package on PyPI is a Python interface library for - Graphviz and does not actually install Graphviz). You can refer to - `the Graphviz documentation `__ on - how to install it. - - Args: - scale (float): scaling factor - filename (str): file path to save image to (format inferred from name) - style (str): - 'plain': B&W graph; - 'color' (default): color input/output/op nodes - - Returns: - Ipython.display.Image: if in Jupyter notebook and not saving to file, - otherwise None. - """ - from qiskit.visualization.dag_visualization import dag_drawer - - return dag_drawer(dag=self, scale=scale, filename=filename, style=style) - - -class _DAGVarType(enum.Enum): - INPUT = enum.auto() - CAPTURE = enum.auto() - DECLARE = enum.auto() - - -class _DAGVarInfo: - __slots__ = ("var", "type", "in_node", "out_node") - - def __init__(self, var: expr.Var, type_: _DAGVarType, in_node: DAGInNode, out_node: DAGOutNode): - self.var = var - self.type = type_ - self.in_node = in_node - self.out_node = out_node - - -def _may_have_additional_wires(node) -> bool: - """Return whether a given :class:`.DAGOpNode` may contain references to additional wires - locations within its :class:`.Operation`. If this is ``True``, it doesn't necessarily mean - that the operation _will_ access memory inherently, but a ``False`` return guarantees that it - won't. - - The memory might be classical bits or classical variables, such as a control-flow operation or a - store. - - Args: - operation (qiskit.dagcircuit.DAGOpNode): the operation to check. - """ - # This is separate to `_additional_wires` because most of the time there won't be any extra - # wires beyond the explicit `qargs` and `cargs` so we want a fast path to be able to skip - # creating and testing a generator for emptiness. - # - # If updating this, you most likely also need to update `_additional_wires`. - return node.condition is not None or ( - not node.is_standard_gate() and isinstance(node.op, (ControlFlowOp, Store)) - ) - - -def _additional_wires(operation) -> Iterable[Clbit | expr.Var]: - """Return an iterable over the additional tracked memory usage in this operation. These - additional wires include (for example, non-exhaustive) bits referred to by a ``condition`` or - the classical variables involved in control-flow operations. - - Args: - operation: the :class:`~.circuit.Operation` instance for a node. - - Returns: - Iterable: the additional wires inherent to this operation. - """ - # If updating this, you likely need to update `_may_have_additional_wires` too. - if (condition := getattr(operation, "condition", None)) is not None: - if isinstance(condition, expr.Expr): - yield from _wires_from_expr(condition) - else: - yield from condition_resources(condition).clbits - if isinstance(operation, ControlFlowOp): - yield from operation.iter_captured_vars() - if isinstance(operation, SwitchCaseOp): - target = operation.target - if isinstance(target, Clbit): - yield target - elif isinstance(target, ClassicalRegister): - yield from target - else: - yield from _wires_from_expr(target) - elif isinstance(operation, Store): - yield from _wires_from_expr(operation.lvalue) - yield from _wires_from_expr(operation.rvalue) - - -def _wires_from_expr(node: expr.Expr) -> Iterable[Clbit | expr.Var]: - for var in expr.iter_vars(node): - if isinstance(var.var, Clbit): - yield var.var - elif isinstance(var.var, ClassicalRegister): - yield from var.var - else: - yield var +from qiskit._accelerate.circuit import DAGCircuit # pylint: disable=unused-import diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 9f35f6eda898..60e2a7465707 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -21,7 +21,6 @@ from qiskit.circuit import ( Clbit, ClassicalRegister, - ControlFlowOp, IfElseOp, WhileLoopOp, SwitchCaseOp, @@ -175,67 +174,3 @@ def _for_loop_eq(node1, node2, bit_indices1, bit_indices2): } _SEMANTIC_EQ_SYMMETRIC = frozenset({"barrier", "swap", "break_loop", "continue_loop"}) - - -# Note: called from dag_node.rs. -def _semantic_eq(node1, node2, bit_indices1, bit_indices2): - """ - Check if DAG nodes are considered equivalent, e.g., as a node_match for - :func:`rustworkx.is_isomorphic_node_match`. - - Args: - node1 (DAGOpNode, DAGInNode, DAGOutNode): A node to compare. - node2 (DAGOpNode, DAGInNode, DAGOutNode): The other node to compare. - bit_indices1 (dict): Dictionary mapping Bit instances to their index - within the circuit containing node1 - bit_indices2 (dict): Dictionary mapping Bit instances to their index - within the circuit containing node2 - - Return: - Bool: If node1 == node2 - """ - if not isinstance(node1, DAGOpNode) or not isinstance(node1, DAGOpNode): - return type(node1) is type(node2) and bit_indices1.get(node1.wire) == bit_indices2.get( - node2.wire - ) - if isinstance(node1.op, ControlFlowOp) and isinstance(node2.op, ControlFlowOp): - # While control-flow operations aren't represented natively in the DAG, we have to do - # some unpleasant dispatching and very manual handling. Once they have more first-class - # support we'll still be dispatching, but it'll look more appropriate (like the dispatch - # based on `DAGOpNode`/`DAGInNode`/`DAGOutNode` that already exists) and less like we're - # duplicating code from the `ControlFlowOp` classes. - if type(node1.op) is not type(node2.op): - return False - comparer = _SEMANTIC_EQ_CONTROL_FLOW.get(type(node1.op)) - if comparer is None: # pragma: no cover - raise RuntimeError(f"unhandled control-flow operation: {type(node1.op)}") - return comparer(node1, node2, bit_indices1, bit_indices2) - - node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] - node1_cargs = [bit_indices1[carg] for carg in node1.cargs] - - node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] - node2_cargs = [bit_indices2[carg] for carg in node2.cargs] - - # For barriers, qarg order is not significant so compare as sets - if node1.op.name == node2.op.name and node1.name in _SEMANTIC_EQ_SYMMETRIC: - node1_qargs = set(node1_qargs) - node1_cargs = set(node1_cargs) - node2_qargs = set(node2_qargs) - node2_cargs = set(node2_cargs) - - return ( - node1_qargs == node2_qargs - and node1_cargs == node2_cargs - and _legacy_condition_eq( - getattr(node1.op, "condition", None), - getattr(node2.op, "condition", None), - bit_indices1, - bit_indices2, - ) - and node1.op == node2.op - ) - - -# Bind semantic_eq from Python to Rust implementation -DAGNode.semantic_eq = staticmethod(_semantic_eq) diff --git a/qiskit/synthesis/two_qubit/two_qubit_decompose.py b/qiskit/synthesis/two_qubit/two_qubit_decompose.py index 86c5cba8295f..633de3a64f78 100644 --- a/qiskit/synthesis/two_qubit/two_qubit_decompose.py +++ b/qiskit/synthesis/two_qubit/two_qubit_decompose.py @@ -639,7 +639,8 @@ def __call__( """ if use_dag: - from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode + from qiskit.dagcircuit.dagcircuit import DAGCircuit + from qiskit.dagcircuit.dagnode import DAGOpNode sequence = self._inner_decomposer( np.asarray(unitary, dtype=complex), @@ -659,7 +660,7 @@ def __call__( op = CircuitInstruction.from_standard( gate, qubits=tuple(q[x] for x in qubits), params=params ) - node = DAGOpNode.from_instruction(op, dag=dag) + node = DAGOpNode.from_instruction(op) dag._apply_op_node_back(node) return dag else: diff --git a/qiskit/transpiler/passes/basis/basis_translator.py b/qiskit/transpiler/passes/basis/basis_translator.py index a5a3936b1d7e..5737385af15b 100644 --- a/qiskit/transpiler/passes/basis/basis_translator.py +++ b/qiskit/transpiler/passes/basis/basis_translator.py @@ -313,10 +313,7 @@ def _replace_node(self, dag, node, instr_map): if node.params: parameter_map = dict(zip(target_params, node.params)) for inner_node in target_dag.topological_op_nodes(): - new_node = DAGOpNode.from_instruction( - inner_node._to_circuit_instruction(), - dag=target_dag, - ) + new_node = DAGOpNode.from_instruction(inner_node._to_circuit_instruction()) new_node.qargs = tuple( node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs ) @@ -366,7 +363,6 @@ def _replace_node(self, dag, node, instr_map): for inner_node in target_dag.topological_op_nodes(): new_node = DAGOpNode.from_instruction( inner_node._to_circuit_instruction(), - dag=target_dag, ) new_node.qargs = tuple( node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py index 73e1d4ac5484..0c6d780f052a 100644 --- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py @@ -58,7 +58,9 @@ def run(self, dag): continue if isinstance(node.op, ControlFlowOp): - node.op = control_flow.map_blocks(self.run, node.op) + dag.substitute_node( + node, control_flow.map_blocks(self.run, node.op), propagate_condition=False + ) continue if self.target is not None: diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index 99bf95147ae2..51e116033bb6 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -66,7 +66,9 @@ def run(self, dag): for node in dag.op_nodes(): if isinstance(node.op, ControlFlowOp): - node.op = control_flow.map_blocks(self.run, node.op) + dag.substitute_node( + node, control_flow.map_blocks(self.run, node.op), propagate_condition=False + ) continue if getattr(node.op, "_directive", False): diff --git a/qiskit/transpiler/passes/calibration/rzx_templates.py b/qiskit/transpiler/passes/calibration/rzx_templates.py index 406e5e75de04..10f4d19ebd9e 100644 --- a/qiskit/transpiler/passes/calibration/rzx_templates.py +++ b/qiskit/transpiler/passes/calibration/rzx_templates.py @@ -20,17 +20,6 @@ from qiskit.circuit.library.templates import rzx -class RZXTemplateMap(Enum): - """Mapping of instruction name to decomposition template.""" - - ZZ1 = rzx.rzx_zz1() - ZZ2 = rzx.rzx_zz2() - ZZ3 = rzx.rzx_zz3() - YZ = rzx.rzx_yz() - XZ = rzx.rzx_xz() - CY = rzx.rzx_cy() - - def rzx_templates(template_list: List[str] = None) -> Dict: """Convenience function to get the cost_dict and templates for template matching. @@ -40,6 +29,17 @@ def rzx_templates(template_list: List[str] = None) -> Dict: Returns: Decomposition templates and cost values. """ + + class RZXTemplateMap(Enum): + """Mapping of instruction name to decomposition template.""" + + ZZ1 = rzx.rzx_zz1() + ZZ2 = rzx.rzx_zz2() + ZZ3 = rzx.rzx_zz3() + YZ = rzx.rzx_yz() + XZ = rzx.rzx_xz() + CY = rzx.rzx_cy() + if template_list is None: template_list = ["zz1", "zz2", "zz3", "yz", "xz", "cy"] diff --git a/qiskit/transpiler/passes/layout/apply_layout.py b/qiskit/transpiler/passes/layout/apply_layout.py index 629dc32061fc..7514ac6b421f 100644 --- a/qiskit/transpiler/passes/layout/apply_layout.py +++ b/qiskit/transpiler/passes/layout/apply_layout.py @@ -118,6 +118,6 @@ def run(self, dag): } out_layout = Layout(final_layout_mapping) self.property_set["final_layout"] = out_layout - new_dag._global_phase = dag._global_phase + new_dag.global_phase = dag.global_phase return new_dag diff --git a/qiskit/transpiler/passes/layout/sabre_layout.py b/qiskit/transpiler/passes/layout/sabre_layout.py index 4ce94ecdb62f..7e7031ec3361 100644 --- a/qiskit/transpiler/passes/layout/sabre_layout.py +++ b/qiskit/transpiler/passes/layout/sabre_layout.py @@ -310,7 +310,7 @@ def run(self, dag): mapped_dag.add_captured_var(var) for var in dag.iter_declared_vars(): mapped_dag.add_declared_var(var) - mapped_dag._global_phase = dag._global_phase + mapped_dag.global_phase = dag.global_phase self.property_set["original_qubit_indices"] = { bit: index for index, bit in enumerate(dag.qubits) } diff --git a/qiskit/transpiler/passes/optimization/commutative_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_cancellation.py index adfc4d73a221..836fa112fd84 100644 --- a/qiskit/transpiler/passes/optimization/commutative_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_cancellation.py @@ -219,5 +219,7 @@ def _handle_control_flow_ops(self, dag): for block in node.op.blocks: new_circ = pass_manager.run(block) mapped_blocks.append(new_circ) - node.op = node.op.replace_blocks(mapped_blocks) + dag.substitute_node( + node, node.op.replace_blocks(mapped_blocks), propagate_condition=False + ) return dag diff --git a/qiskit/transpiler/passes/optimization/consolidate_blocks.py b/qiskit/transpiler/passes/optimization/consolidate_blocks.py index 12f7285af9dc..49f227e8a746 100644 --- a/qiskit/transpiler/passes/optimization/consolidate_blocks.py +++ b/qiskit/transpiler/passes/optimization/consolidate_blocks.py @@ -202,7 +202,11 @@ def _handle_control_flow_ops(self, dag): for node in dag.op_nodes(): if node.name not in CONTROL_FLOW_OP_NAMES: continue - node.op = node.op.replace_blocks(pass_manager.run(block) for block in node.op.blocks) + dag.substitute_node( + node, + node.op.replace_blocks(pass_manager.run(block) for block in node.op.blocks), + propagate_condition=False, + ) return dag def _check_not_in_basis(self, dag, gate_name, qargs): diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py index e7c502c9ef9f..181f02e312b3 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py @@ -242,10 +242,8 @@ def run(self, dag): qubit = run[0].qargs for gate, angles in best_circuit_sequence: op = CircuitInstruction.from_standard(gate, qubit, angles) - node = DAGOpNode.from_instruction(op, dag=dag) - node._node_id = dag._multi_graph.add_node(node) - dag._increment_op(gate.name) - dag._multi_graph.insert_node_on_in_edges(node._node_id, first_node_id) + node = DAGOpNode.from_instruction(op) + dag._insert_1q_on_incoming_qubit(node, first_node_id) dag.global_phase += best_circuit_sequence.global_phase # Delete the other nodes in the run for current_node in run: diff --git a/qiskit/transpiler/passes/optimization/optimize_annotated.py b/qiskit/transpiler/passes/optimization/optimize_annotated.py index fe6fe7f49e78..0a583259c800 100644 --- a/qiskit/transpiler/passes/optimization/optimize_annotated.py +++ b/qiskit/transpiler/passes/optimization/optimize_annotated.py @@ -125,7 +125,9 @@ def _run_inner(self, dag) -> Tuple[DAGCircuit, bool]: # Handle control-flow for node in dag.op_nodes(): if isinstance(node.op, ControlFlowOp): - node.op = control_flow.map_blocks(self.run, node.op) + dag.substitute_node( + node, control_flow.map_blocks(self.run, node.op), propagate_condition=False + ) # First, optimize every node in the DAG. dag, opt1 = self._canonicalize(dag) @@ -163,7 +165,7 @@ def _canonicalize(self, dag) -> Tuple[DAGCircuit, bool]: node.op.modifiers = canonical_modifiers else: # no need for annotated operations - node.op = cur + dag.substitute_node(node, cur, propagate_condition=False) did_something = True return dag, did_something diff --git a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py index 7508c9440a6e..ac04043a27fa 100644 --- a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py +++ b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py @@ -14,7 +14,8 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.circuit.quantumcircuitdata import CircuitInstruction -from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode +from qiskit.dagcircuit.dagcircuit import DAGCircuit +from qiskit.dagcircuit.dagnode import DAGOpNode from qiskit.circuit.library.generalized_gates import UnitaryGate from qiskit.synthesis.two_qubit.two_qubit_decompose import TwoQubitWeylDecomposition @@ -60,12 +61,12 @@ def run(self, dag: DAGCircuit): ur = decomp.K1r ur_node = DAGOpNode.from_instruction( - CircuitInstruction(UnitaryGate(ur), qubits=(node.qargs[0],)), dag=new_dag + CircuitInstruction(UnitaryGate(ur), qubits=(node.qargs[0],)) ) ul = decomp.K1l ul_node = DAGOpNode.from_instruction( - CircuitInstruction(UnitaryGate(ul), qubits=(node.qargs[1],)), dag=new_dag + CircuitInstruction(UnitaryGate(ul), qubits=(node.qargs[1],)) ) new_dag._apply_op_node_back(ur_node) new_dag._apply_op_node_back(ul_node) diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index 788f0d995754..9edd1ceee445 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -372,7 +372,7 @@ def empty_dag(block): empty.add_clbits(block.clbits) for creg in block.cregs: empty.add_creg(creg) - empty._global_phase = block.global_phase + empty.global_phase = block.global_phase return empty def apply_swaps(dest_dag, swaps, layout): @@ -388,7 +388,7 @@ def recurse(dest_dag, source_dag, result, root_logical_map, layout): the virtual qubit in the root source DAG that it is bound to.""" swap_map, node_order, node_block_results = result for node_id in node_order: - node = source_dag._multi_graph[node_id] + node = source_dag.node(node_id) if node_id in swap_map: apply_swaps(dest_dag, swap_map[node_id], layout) if not node.is_control_flow(): diff --git a/qiskit/transpiler/passes/routing/stochastic_swap.py b/qiskit/transpiler/passes/routing/stochastic_swap.py index a3ebbd6cbdde..efbd7e37f626 100644 --- a/qiskit/transpiler/passes/routing/stochastic_swap.py +++ b/qiskit/transpiler/passes/routing/stochastic_swap.py @@ -223,7 +223,7 @@ def _layer_permutation(self, dag, layer_partition, layout, qubit_subset, couplin int_layout = nlayout.NLayout(layout_mapping, num_qubits, coupling.size()) trial_circuit = DAGCircuit() # SWAP circuit for slice of swaps in this trial - trial_circuit.add_qubits(layout.get_virtual_bits()) + trial_circuit.add_qubits(list(layout.get_virtual_bits())) edges = np.asarray(coupling.get_edges(), dtype=np.uint32).ravel() cdist = coupling._dist_matrix @@ -273,9 +273,7 @@ def _layer_update(self, dag, layer, best_layout, best_depth, best_circuit): # Output any swaps if best_depth > 0: logger.debug("layer_update: there are swaps in this layer, depth %d", best_depth) - dag.compose( - best_circuit, qubits={bit: bit for bit in best_circuit.qubits}, inline_captures=True - ) + dag.compose(best_circuit, qubits=list(best_circuit.qubits), inline_captures=True) else: logger.debug("layer_update: there are no swaps in this layer") # Output this layer diff --git a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py index 0e351161f7df..2217d32f847c 100644 --- a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +++ b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py @@ -370,7 +370,10 @@ def _pad( op = prev_node.op theta_l, phi_l, lam_l = op.params op.params = Optimize1qGates.compose_u3(theta, phi, lam, theta_l, phi_l, lam_l) - prev_node.op = op + new_prev_node = dag.substitute_node(prev_node, op, propagate_condition=False) + start_time = self.property_set["node_start_time"].pop(prev_node) + if start_time is not None: + self.property_set["node_start_time"][new_prev_node] = start_time sequence_gphase += phase else: # Don't do anything if there's no single-qubit gate to absorb the inverse diff --git a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py index 2c7c97ec856a..d9f3d77f2915 100644 --- a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +++ b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py @@ -72,9 +72,9 @@ def _get_node_duration( # Note that node duration is updated (but this is analysis pass) op = node.op.to_mutable() op.duration = duration - node.op = op + dag.substitute_node(node, op, propagate_condition=False) else: - duration = node.op.duration + duration = node.duration if isinstance(duration, ParameterExpression): raise TranspilerError( diff --git a/qiskit/transpiler/passes/scheduling/time_unit_conversion.py b/qiskit/transpiler/passes/scheduling/time_unit_conversion.py index 08ac932d8aeb..f4f70210b785 100644 --- a/qiskit/transpiler/passes/scheduling/time_unit_conversion.py +++ b/qiskit/transpiler/passes/scheduling/time_unit_conversion.py @@ -108,7 +108,7 @@ def run(self, dag: DAGCircuit): op = node.op.to_mutable() op.duration = duration op.unit = time_unit - node.op = op + dag.substitute_node(node, op, propagate_condition=False) self.property_set["time_unit"] = time_unit return dag diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index 38c46547b12d..73a402dc202f 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -303,8 +303,10 @@ def _run(self, dag: DAGCircuit, tracker: QubitTracker) -> DAGCircuit: # next check control flow elif node.is_control_flow(): - node.op = control_flow.map_blocks( - partial(self._run, tracker=tracker.copy()), node.op + dag.substitute_node( + node, + control_flow.map_blocks(partial(self._run, tracker=tracker.copy()), node.op), + propagate_condition=False, ) # now we are free to synthesize diff --git a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py index 4054a158d12a..e31f6918f452 100644 --- a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py @@ -52,7 +52,8 @@ RGate, ) from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode +from qiskit.dagcircuit.dagcircuit import DAGCircuit +from qiskit.dagcircuit.dagnode import DAGOpNode from qiskit.exceptions import QiskitError from qiskit.providers.models.backendproperties import BackendProperties from qiskit.quantum_info import Operator @@ -511,7 +512,7 @@ def _run_main_loop( for node in dag.op_nodes(): if node.name not in CONTROL_FLOW_OP_NAMES: continue - node.op = node.op.replace_blocks( + new_op = node.op.replace_blocks( [ dag_to_circuit( self._run_main_loop( @@ -530,6 +531,7 @@ def _run_main_loop( for block in node.op.blocks ] ) + dag.substitute_node(node, new_op, propagate_condition=False) out_dag = dag.copy_empty_like() for node in dag.topological_op_nodes(): @@ -572,15 +574,13 @@ def _run_main_loop( user_gate_node._to_circuit_instruction().replace( params=user_gate_node.params, qubits=tuple(qubits[x] for x in qargs), - ), - dag=out_dag, + ) ) else: node = DAGOpNode.from_instruction( CircuitInstruction.from_standard( gate, tuple(qubits[x] for x in qargs), params - ), - dag=out_dag, + ) ) out_dag._apply_op_node_back(node) out_dag.global_phase += global_phase diff --git a/qiskit/transpiler/passes/utils/control_flow.py b/qiskit/transpiler/passes/utils/control_flow.py index 3739852b4c7e..27c3c83d53c7 100644 --- a/qiskit/transpiler/passes/utils/control_flow.py +++ b/qiskit/transpiler/passes/utils/control_flow.py @@ -45,7 +45,7 @@ def trivial_recurse(method): use :func:`map_blocks` as:: if isinstance(node.op, ControlFlowOp): - node.op = map_blocks(self.run, node.op) + dag.substitute_node(node, map_blocks(self.run, node.op)) from with :meth:`.BasePass.run`.""" @@ -55,7 +55,9 @@ def bound_wrapped_method(dag): return out(self, dag) for node in dag.op_nodes(ControlFlowOp): - node.op = map_blocks(bound_wrapped_method, node.op) + dag.substitute_node( + node, map_blocks(bound_wrapped_method, node.op), propagate_condition=False + ) return method(self, dag) return out diff --git a/qiskit/transpiler/passes/utils/gate_direction.py b/qiskit/transpiler/passes/utils/gate_direction.py index 79493ae8ad25..8ea77f7ccd46 100644 --- a/qiskit/transpiler/passes/utils/gate_direction.py +++ b/qiskit/transpiler/passes/utils/gate_direction.py @@ -175,7 +175,7 @@ def _run_coupling_map(self, dag, wire_map, edges=None): # Don't include directives to avoid things like barrier, which are assumed always supported. for node in dag.op_nodes(include_directives=False): if isinstance(node.op, ControlFlowOp): - node.op = node.op.replace_blocks( + new_op = node.op.replace_blocks( dag_to_circuit( self._run_coupling_map( circuit_to_dag(block), @@ -188,6 +188,7 @@ def _run_coupling_map(self, dag, wire_map, edges=None): ) for block in node.op.blocks ) + dag.substitute_node(node, new_op, propagate_condition=False) continue if len(node.qargs) != 2: continue @@ -222,7 +223,7 @@ def _run_target(self, dag, wire_map): # Don't include directives to avoid things like barrier, which are assumed always supported. for node in dag.op_nodes(include_directives=False): if isinstance(node.op, ControlFlowOp): - node.op = node.op.replace_blocks( + new_op = node.op.replace_blocks( dag_to_circuit( self._run_target( circuit_to_dag(block), @@ -234,6 +235,7 @@ def _run_target(self, dag, wire_map): ) for block in node.op.blocks ) + dag.substitute_node(node, new_op, propagate_condition=False) continue if len(node.qargs) != 2: continue diff --git a/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py b/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py index 40390a02cade..acb748bb6f95 100644 --- a/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +++ b/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py @@ -108,7 +108,7 @@ def _collect_potential_merges(dag, barriers): for next_barrier in barriers[1:]: # Ensure barriers are adjacent before checking if they are mergeable. - if dag._multi_graph.has_edge(end_of_barrier._node_id, next_barrier._node_id): + if dag._has_edge(end_of_barrier._node_id, next_barrier._node_id): # Remove all barriers that have already been included in this new barrier from the # set of ancestors/descendants as they will be removed from the new DAG when it is diff --git a/qiskit/visualization/circuit/_utils.py b/qiskit/visualization/circuit/_utils.py index e6ee03905d27..d933d38b5c4a 100644 --- a/qiskit/visualization/circuit/_utils.py +++ b/qiskit/visualization/circuit/_utils.py @@ -454,14 +454,12 @@ def _get_layered_instructions( clbits = new_clbits dag = circuit_to_dag(circuit) - dag.qubits = qubits - dag.clbits = clbits if justify == "none": for node in dag.topological_op_nodes(): nodes.append([node]) else: - nodes = _LayerSpooler(dag, justify, measure_map) + nodes = _LayerSpooler(dag, qubits, clbits, justify, measure_map) # Optionally remove all idle wires and instructions that are on them and # on them only. @@ -515,23 +513,25 @@ def _get_gate_span(qubits, node): def _any_crossover(qubits, node, nodes): """Return True .IFF. 'node' crosses over any 'nodes'.""" - gate_span = _get_gate_span(qubits, node) - all_indices = [] - for check_node in nodes: - if check_node != node: - all_indices += _get_gate_span(qubits, check_node) - return any(i in gate_span for i in all_indices) + return bool( + set(_get_gate_span(qubits, node)).intersection( + bit for check_node in nodes for bit in _get_gate_span(qubits, check_node) + ) + ) + + +_GLOBAL_NID = 0 class _LayerSpooler(list): """Manipulate list of layer dicts for _get_layered_instructions.""" - def __init__(self, dag, justification, measure_map): + def __init__(self, dag, qubits, clbits, justification, measure_map): """Create spool""" super().__init__() self.dag = dag - self.qubits = dag.qubits - self.clbits = dag.clbits + self.qubits = qubits + self.clbits = clbits self.justification = justification self.measure_map = measure_map self.cregs = [self.dag.cregs[reg] for reg in self.dag.cregs] @@ -660,6 +660,15 @@ def slide_from_right(self, node, index): def add(self, node, index): """Add 'node' where it belongs, starting the try at 'index'.""" + # Before we add the node, we set its node ID to be globally unique + # within this spooler. This is necessary because nodes may span + # layers (which are separate DAGs), and thus can falsely compare + # as equal if their contents and node IDs happen to be the same. + # This is particularly important for the matplotlib drawer, which + # keys several of its internal data structures with these nodes. + global _GLOBAL_NID # pylint: disable=global-statement + node._node_id = _GLOBAL_NID + _GLOBAL_NID += 1 if self.justification == "left": self.slide_from_left(node, index) else: diff --git a/qiskit/visualization/dag_visualization.py b/qiskit/visualization/dag_visualization.py index dae97b51b0a4..a6a111fe75e9 100644 --- a/qiskit/visualization/dag_visualization.py +++ b/qiskit/visualization/dag_visualization.py @@ -15,9 +15,14 @@ """ Visualization function for DAG circuit representation. """ + +import io +import subprocess + from rustworkx.visualization import graphviz_draw from qiskit.dagcircuit.dagnode import DAGOpNode, DAGInNode, DAGOutNode +from qiskit.dagcircuit.dagcircuit import DAGCircuit from qiskit.circuit import Qubit, Clbit, ClassicalRegister from qiskit.circuit.classical import expr from qiskit.converters import dagdependency_to_circuit @@ -26,7 +31,48 @@ from .exceptions import VisualizationError +IMAGE_TYPES = { + "canon", + "cmap", + "cmapx", + "cmapx_np", + "dia", + "dot", + "fig", + "gd", + "gd2", + "gif", + "hpgl", + "imap", + "imap_np", + "ismap", + "jpe", + "jpeg", + "jpg", + "mif", + "mp", + "pcl", + "pdf", + "pic", + "plain", + "plain-ext", + "png", + "ps", + "ps2", + "svg", + "svgz", + "vml", + "vmlz", + "vrml", + "vtx", + "wbmp", + "xdor", + "xlib", +} + + @_optionals.HAS_GRAPHVIZ.require_in_call +@_optionals.HAS_PIL.require_in_call def dag_drawer(dag, scale=0.7, filename=None, style="color"): """Plot the directed acyclic graph (dag) to represent operation dependencies in a quantum circuit. @@ -48,6 +94,8 @@ def dag_drawer(dag, scale=0.7, filename=None, style="color"): Raises: VisualizationError: when style is not recognized. InvalidFileError: when filename provided is not valid + ValueError: If the file extension for ``filename`` is not an image + type supported by Graphviz. Example: .. plot:: @@ -69,6 +117,7 @@ def dag_drawer(dag, scale=0.7, filename=None, style="color"): dag = circuit_to_dag(circ) dag_drawer(dag) """ + from PIL import Image # NOTE: use type str checking to avoid potential cyclical import # the two tradeoffs ere that it will not handle subclasses and it is @@ -215,16 +264,53 @@ def edge_attr_func(edge): e["label"] = label return e - image_type = None + image_type = "png" if filename: if "." not in filename: raise InvalidFileError("Parameter 'filename' must be in format 'name.extension'") image_type = filename.split(".")[-1] - return graphviz_draw( - dag._multi_graph, - node_attr_func, - edge_attr_func, - graph_attrs, - filename, - image_type, - ) + if image_type not in IMAGE_TYPES: + raise ValueError( + "The specified value for the image_type argument, " + f"'{image_type}' is not a valid choice. It must be one of: " + f"{IMAGE_TYPES}" + ) + + if isinstance(dag, DAGCircuit): + dot_str = dag._to_dot( + graph_attrs, + node_attr_func, + edge_attr_func, + ) + + prog = "dot" + if not filename: + dot_result = subprocess.run( + [prog, "-T", image_type], + input=dot_str.encode("utf-8"), + capture_output=True, + encoding=None, + check=True, + text=False, + ) + dot_bytes_image = io.BytesIO(dot_result.stdout) + image = Image.open(dot_bytes_image) + return image + else: + subprocess.run( + [prog, "-T", image_type, "-o", filename], + input=dot_str, + check=True, + encoding="utf8", + text=True, + ) + return None + else: + return graphviz_draw( + dag._multi_graph, + node_attr_func, + edge_attr_func, + graph_attrs, + filename, + image_type, + ) diff --git a/releasenotes/notes/dag-oxide-60b3d7219cb21703.yaml b/releasenotes/notes/dag-oxide-60b3d7219cb21703.yaml new file mode 100644 index 000000000000..090a8226c111 --- /dev/null +++ b/releasenotes/notes/dag-oxide-60b3d7219cb21703.yaml @@ -0,0 +1,49 @@ +--- +features_transpiler: + - | + The implementation of the :class:`.DAGCircuit` has been rewritten in Rust. This rewrite of + the Python class should be fully API compatible with the previous Python implementation of + the class. While the class was previously implemented using + `rustworkx `__ and its underlying data graph structure existed + in Rust, the implementation of the class and all the data was stored in Python. This new + version of :class:`.DAGCircuit` stores a Rust native representation for all its data and + is fully implemented in Rust. This new implementation should be more efficient in memory + usage as it compresses the qubit and clbit representation for instructions at rest. + It also enables speed up for transpiler passes as they can fully manipulate a + :class:`.DAGCircuit` from Rust. +upgrade_transpiler: + - | + :class:`.DAGNode` objects (and its subclasses :class:`.DAGInNode`, :class:`.DAGOutNode`, and + :class:`.DAGOpNode`) no longer return references to the same underlying object from + :class:`.DAGCircuit` methods. This was never a guarantee before that all returned nodes would + be shared reference to the same object, but with the migration of the :class:`.DAGCircuit` to + Rust when a :class:`.DAGNode` a new :class:`.DAGNode` instance is generated on the fly when + a node is returned to Python. These objects will evaluate as equal using ``==`` or similar + checks that rely on ``__eq__`` but will no longer identify as the same object. + - | + The :class:`.DAGOpNode` instances returned from the :class:`.DAGCircuit` are no longer shared + references to the underlying data stored on the DAG. In previous release it was possible to + do something like:: + + for node in dag.op_nodes(): + node.op = new_op + + however this type of mutation was always unsound as it could break the DAG's internal caching + and cause corruption of the data structure. Instead you should use the API provided by + :class:`.DAGCircuit` for mutation such as :meth:`.DAGCircuit.substitute_node`, + :meth:`.DAGCircuit.substitute_node_with_dag`, or :meth:`.DAGCircuit.contract_node`. For example + the above code block would become:: + + for node in dag.op_nodes(): + dag.substitute_node(node, new_op) + + This is similar to an upgrade note from 1.2.0 where this was noted on for mutation of the + :attr:`.DAGOpNode.op` attribute, not the :class:`.DAGOpNode` itself. However in 1.3 this extends + to the entire object, not just it's inner ``op`` attribute. In general this type of mutation was + always unsound and not supported, but could previously have potentially worked in some cases. +fixes: + - | + Fixed an issue with :meth:`.DAGCircuit.apply_operation_back` and + :meth:`.DAGCircuit.apply_operation_front` where previously if you set a + :class:`.Clbit` object to the input for the ``qargs`` argument it would silently be accepted. + This has been fixed so the type mismatch is correctly identified and an exception is raised. diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index c3a930aed1f2..edb3df63e46d 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -3320,19 +3320,19 @@ def _visit_block(circuit, qubit_mapping=None): tqc_dag = circuit_to_dag(tqc) qubit_map = {qubit: index for index, qubit in enumerate(tqc_dag.qubits)} input_node = tqc_dag.input_map[tqc_dag.clbits[0]] - first_meas_node = tqc_dag._multi_graph.find_successors_by_edge( + first_meas_node = tqc_dag._find_successors_by_edge( input_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] # The first node should be a measurement self.assertIsInstance(first_meas_node.op, Measure) # This should be in the first component self.assertIn(qubit_map[first_meas_node.qargs[0]], components[0]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( first_meas_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] while isinstance(op_node, DAGOpNode): self.assertIn(qubit_map[op_node.qargs[0]], components[1]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( op_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] @@ -3394,19 +3394,19 @@ def _visit_block(circuit, qubit_mapping=None): tqc_dag = circuit_to_dag(tqc) qubit_map = {qubit: index for index, qubit in enumerate(tqc_dag.qubits)} input_node = tqc_dag.input_map[tqc_dag.clbits[0]] - first_meas_node = tqc_dag._multi_graph.find_successors_by_edge( + first_meas_node = tqc_dag._find_successors_by_edge( input_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] # The first node should be a measurement self.assertIsInstance(first_meas_node.op, Measure) # This should be in the first component self.assertIn(qubit_map[first_meas_node.qargs[0]], components[0]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( first_meas_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] while isinstance(op_node, DAGOpNode): self.assertIn(qubit_map[op_node.qargs[0]], components[1]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( op_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] @@ -3477,26 +3477,26 @@ def _visit_block(circuit, qubit_mapping=None): tqc_dag = circuit_to_dag(tqc) qubit_map = {qubit: index for index, qubit in enumerate(tqc_dag.qubits)} input_node = tqc_dag.input_map[tqc_dag.clbits[0]] - first_meas_node = tqc_dag._multi_graph.find_successors_by_edge( + first_meas_node = tqc_dag._find_successors_by_edge( input_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] self.assertIsInstance(first_meas_node.op, Measure) self.assertIn(qubit_map[first_meas_node.qargs[0]], components[0]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( first_meas_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] while not isinstance(op_node.op, Measure): self.assertIn(qubit_map[op_node.qargs[0]], components[1]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( op_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] self.assertIn(qubit_map[op_node.qargs[0]], components[1]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( op_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] while not isinstance(op_node.op, Measure): self.assertIn(qubit_map[op_node.qargs[0]], components[2]) - op_node = tqc_dag._multi_graph.find_successors_by_edge( + op_node = tqc_dag._find_successors_by_edge( op_node._node_id, lambda edge_data: isinstance(edge_data, Clbit) )[0] self.assertIn(qubit_map[op_node.qargs[0]], components[2]) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 26f7e4788083..ef8050961066 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -18,7 +18,6 @@ import unittest from ddt import ddt, data -import rustworkx as rx from numpy import pi from qiskit.dagcircuit import DAGCircuit, DAGOpNode, DAGInNode, DAGOutNode, DAGCircuitError @@ -55,18 +54,16 @@ def raise_if_dagcircuit_invalid(dag): DAGCircuitError: if DAGCircuit._multi_graph is inconsistent. """ - multi_graph = dag._multi_graph - - if not rx.is_directed_acyclic_graph(multi_graph): + if not dag._is_dag(): raise DAGCircuitError("multi_graph is not a DAG.") # Every node should be of type in, out, or op. # All input/output nodes should be present in input_map/output_map. - for node in dag._multi_graph.nodes(): + for node in dag.nodes(): if isinstance(node, DAGInNode): - assert node is dag.input_map[node.wire] + assert node == dag.input_map[node.wire] elif isinstance(node, DAGOutNode): - assert node is dag.output_map[node.wire] + assert node == dag.output_map[node.wire] elif isinstance(node, DAGOpNode): continue else: @@ -78,9 +75,7 @@ def raise_if_dagcircuit_invalid(dag): assert len(node.cargs) == node.op.num_clbits # Every edge should be labled with a known wire. - edges_outside_wires = [ - edge_data for edge_data in dag._multi_graph.edges() if edge_data not in dag.wires - ] + edges_outside_wires = [edge_data for edge_data in dag._edges() if edge_data not in dag.wires] if edges_outside_wires: raise DAGCircuitError( f"multi_graph contains one or more edges ({edges_outside_wires}) " @@ -103,7 +98,7 @@ def raise_if_dagcircuit_invalid(dag): out_node_id = dag.output_map[wire]._node_id while cur_node_id != out_node_id: - out_edges = dag._multi_graph.out_edges(cur_node_id) + out_edges = dag._out_edges(cur_node_id) edges_to_follow = [(src, dest, data) for (src, dest, data) in out_edges if data == wire] assert len(edges_to_follow) == 1 @@ -112,18 +107,15 @@ def raise_if_dagcircuit_invalid(dag): # Wires can only terminate at input/output nodes. op_counts = Counter() for op_node in dag.op_nodes(): - assert multi_graph.in_degree(op_node._node_id) == multi_graph.out_degree(op_node._node_id) + assert sum(1 for _ in dag.predecessors(op_node)) == sum(1 for _ in dag.successors(op_node)) op_counts[op_node.name] += 1 # The _op_names attribute should match the counted op names - assert op_counts == dag._op_names + assert op_counts == dag.count_ops() # Node input/output edges should match node qarg/carg/condition. for node in dag.op_nodes(): - in_edges = dag._multi_graph.in_edges(node._node_id) - out_edges = dag._multi_graph.out_edges(node._node_id) - - in_wires = {data for src, dest, data in in_edges} - out_wires = {data for src, dest, data in out_edges} + in_wires = set(dag._in_wires(node._node_id)) + out_wires = set(dag._out_wires(node._node_id)) node_cond_bits = set( node.op.condition[0][:] if getattr(node.op, "condition", None) is not None else [] @@ -516,6 +508,38 @@ def test_remove_unknown_clbit(self): self.assert_cregs_equal(self.original_cregs) self.assert_clbits_equal(self.original_clbits) + def test_remove_clbit_with_control_flow(self): + """Test clbit removal in the middle of clbits with control flow.""" + qr = QuantumRegister(1) + cr1 = ClassicalRegister(2, "a") + cr2 = ClassicalRegister(2, "b") + clbit = Clbit() + dag = DAGCircuit() + dag.add_qreg(qr) + dag.add_creg(cr1) + dag.add_creg(cr2) + dag.add_clbits([clbit]) + + inner = QuantumCircuit(1) + inner.h(0) + inner.z(0) + + op = IfElseOp(expr.logic_and(expr.equal(cr1, 3), expr.logic_not(clbit)), inner, None) + dag.apply_operation_back(op, qr, ()) + dag.remove_clbits(*cr2) + self.assertEqual(dag.clbits, list(cr1) + [clbit]) + self.assertEqual(dag.cregs, {"a": cr1}) + + expected = DAGCircuit() + expected.add_qreg(qr) + expected.add_creg(cr1) + expected.add_clbits([clbit]) + + op = IfElseOp(expr.logic_and(expr.equal(cr1, 3), expr.logic_not(clbit)), inner, None) + expected.apply_operation_back(op, qr, ()) + + self.assertEqual(dag, expected) + class TestDagApplyOperation(QiskitTestCase): """Test adding an op node to a dag.""" @@ -575,7 +599,7 @@ def test_apply_operation_back_conditional(self): self.assertEqual(h_node.op.condition, h_gate.condition) self.assertEqual( - sorted(self.dag._multi_graph.in_edges(h_node._node_id)), + sorted(self.dag._in_edges(h_node._node_id)), sorted( [ (self.dag.input_map[self.qubit2]._node_id, h_node._node_id, self.qubit2), @@ -586,7 +610,7 @@ def test_apply_operation_back_conditional(self): ) self.assertEqual( - sorted(self.dag._multi_graph.out_edges(h_node._node_id)), + sorted(self.dag._out_edges(h_node._node_id)), sorted( [ (h_node._node_id, self.dag.output_map[self.qubit2]._node_id, self.qubit2), @@ -596,7 +620,7 @@ def test_apply_operation_back_conditional(self): ), ) - self.assertTrue(rx.is_directed_acyclic_graph(self.dag._multi_graph)) + self.assertTrue(self.dag._is_dag()) def test_apply_operation_back_conditional_measure(self): """Test consistency of apply_operation_back for conditional measure.""" @@ -615,7 +639,7 @@ def test_apply_operation_back_conditional_measure(self): self.assertEqual(meas_node.op.condition, meas_gate.condition) self.assertEqual( - sorted(self.dag._multi_graph.in_edges(meas_node._node_id)), + sorted(self.dag._in_edges(meas_node._node_id)), sorted( [ (self.dag.input_map[self.qubit0]._node_id, meas_node._node_id, self.qubit0), @@ -630,7 +654,7 @@ def test_apply_operation_back_conditional_measure(self): ) self.assertEqual( - sorted(self.dag._multi_graph.out_edges(meas_node._node_id)), + sorted(self.dag._out_edges(meas_node._node_id)), sorted( [ (meas_node._node_id, self.dag.output_map[self.qubit0]._node_id, self.qubit0), @@ -644,7 +668,7 @@ def test_apply_operation_back_conditional_measure(self): ), ) - self.assertTrue(rx.is_directed_acyclic_graph(self.dag._multi_graph)) + self.assertTrue(self.dag._is_dag()) def test_apply_operation_back_conditional_measure_to_self(self): """Test consistency of apply_operation_back for measure onto conditioning bit.""" @@ -660,7 +684,7 @@ def test_apply_operation_back_conditional_measure_to_self(self): self.assertEqual(meas_node.op.condition, meas_gate.condition) self.assertEqual( - sorted(self.dag._multi_graph.in_edges(meas_node._node_id)), + sorted(self.dag._in_edges(meas_node._node_id)), sorted( [ (self.dag.input_map[self.qubit1]._node_id, meas_node._node_id, self.qubit1), @@ -671,7 +695,7 @@ def test_apply_operation_back_conditional_measure_to_self(self): ) self.assertEqual( - sorted(self.dag._multi_graph.out_edges(meas_node._node_id)), + sorted(self.dag._out_edges(meas_node._node_id)), sorted( [ (meas_node._node_id, self.dag.output_map[self.qubit1]._node_id, self.qubit1), @@ -681,7 +705,7 @@ def test_apply_operation_back_conditional_measure_to_self(self): ), ) - self.assertTrue(rx.is_directed_acyclic_graph(self.dag._multi_graph)) + self.assertTrue(self.dag._is_dag()) def test_apply_operation_front(self): """The apply_operation_front() method""" @@ -935,8 +959,8 @@ def test_classical_predecessors(self): self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(HGate(), [self.qubit1], []) - self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0], []) - self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], []) + self.dag.apply_operation_back(Measure(), [self.qubit0], [self.clbit0]) + self.dag.apply_operation_back(Measure(), [self.qubit1], [self.clbit1]) predecessor_measure = self.dag.classical_predecessors(self.dag.named_nodes("measure").pop()) @@ -948,6 +972,13 @@ def test_classical_predecessors(self): self.assertIsInstance(predecessor1, DAGInNode) self.assertIsInstance(predecessor1.wire, Clbit) + def test_apply_operation_reject_invalid_qarg_carg(self): + """Test that we can't add a carg to qargs and vice versa on apply methods""" + with self.assertRaises(KeyError): + self.dag.apply_operation_back(Measure(), [self.clbit1], [self.qubit1]) + with self.assertRaises(KeyError): + self.dag.apply_operation_front(Measure(), [self.clbit1], [self.qubit1]) + def test_classical_successors(self): """The method dag.classical_successors() returns successors connected by classical edges""" @@ -969,8 +1000,8 @@ def test_classical_successors(self): self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(HGate(), [self.qubit1], []) - self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0], []) - self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], []) + self.dag.apply_operation_back(Measure(), [self.qubit0], [self.clbit0]) + self.dag.apply_operation_back(Measure(), [self.qubit1], [self.clbit1]) successors_measure = self.dag.classical_successors(self.dag.named_nodes("measure").pop()) @@ -1067,12 +1098,12 @@ def test_topological_nodes(self): ("cx", (self.qubit2, self.qubit1)), ("cx", (self.qubit0, self.qubit2)), ("h", (self.qubit2,)), + cr[0], + cr[1], qr[0], qr[1], qr[2], cr[0], - cr[0], - cr[1], cr[1], ] self.assertEqual( @@ -2397,7 +2428,6 @@ def test_contract_var_use_to_nothing(self): expected = DAGCircuit() expected.add_input_var(a) - self.assertEqual(src, expected) def test_raise_if_var_mismatch(self): @@ -2665,7 +2695,6 @@ def test_substituting_node_preserves_args_condition(self, inplace): self.assertEqual(replacement_node.qargs, (qr[1], qr[0])) self.assertEqual(replacement_node.cargs, ()) self.assertEqual(replacement_node.op.condition, (cr, 1)) - self.assertEqual(replacement_node is node_to_be_replaced, inplace) @data(True, False) @@ -3172,24 +3201,34 @@ def test_creg_conditional(self): self.assertEqual(gate_node.qargs, (self.qreg[0],)) self.assertEqual(gate_node.cargs, ()) self.assertEqual(gate_node.op.condition, (self.creg, 1)) + + gate_node_preds = list(self.dag.predecessors(gate_node)) + gate_node_in_edges = [ + (src._node_id, wire) + for (src, tgt, wire) in self.dag.edges(gate_node_preds) + if tgt == gate_node + ] + self.assertEqual( - sorted(self.dag._multi_graph.in_edges(gate_node._node_id)), + sorted(gate_node_in_edges), sorted( [ - (self.dag.input_map[self.qreg[0]]._node_id, gate_node._node_id, self.qreg[0]), - (self.dag.input_map[self.creg[0]]._node_id, gate_node._node_id, self.creg[0]), - (self.dag.input_map[self.creg[1]]._node_id, gate_node._node_id, self.creg[1]), + (self.dag.input_map[self.qreg[0]]._node_id, self.qreg[0]), + (self.dag.input_map[self.creg[0]]._node_id, self.creg[0]), + (self.dag.input_map[self.creg[1]]._node_id, self.creg[1]), ] ), ) + gate_node_out_edges = [(tgt._node_id, wire) for (_, tgt, wire) in self.dag.edges(gate_node)] + self.assertEqual( - sorted(self.dag._multi_graph.out_edges(gate_node._node_id)), + sorted(gate_node_out_edges), sorted( [ - (gate_node._node_id, self.dag.output_map[self.qreg[0]]._node_id, self.qreg[0]), - (gate_node._node_id, self.dag.output_map[self.creg[0]]._node_id, self.creg[0]), - (gate_node._node_id, self.dag.output_map[self.creg[1]]._node_id, self.creg[1]), + (self.dag.output_map[self.qreg[0]]._node_id, self.qreg[0]), + (self.dag.output_map[self.creg[0]]._node_id, self.creg[0]), + (self.dag.output_map[self.creg[1]]._node_id, self.creg[1]), ] ), ) @@ -3204,22 +3243,31 @@ def test_clbit_conditional(self): self.assertEqual(gate_node.qargs, (self.qreg[0],)) self.assertEqual(gate_node.cargs, ()) self.assertEqual(gate_node.op.condition, (self.creg[0], 1)) + + gate_node_preds = list(self.dag.predecessors(gate_node)) + gate_node_in_edges = [ + (src._node_id, wire) + for (src, tgt, wire) in self.dag.edges(gate_node_preds) + if tgt == gate_node + ] + self.assertEqual( - sorted(self.dag._multi_graph.in_edges(gate_node._node_id)), + sorted(gate_node_in_edges), sorted( [ - (self.dag.input_map[self.qreg[0]]._node_id, gate_node._node_id, self.qreg[0]), - (self.dag.input_map[self.creg[0]]._node_id, gate_node._node_id, self.creg[0]), + (self.dag.input_map[self.qreg[0]]._node_id, self.qreg[0]), + (self.dag.input_map[self.creg[0]]._node_id, self.creg[0]), ] ), ) + gate_node_out_edges = [(tgt._node_id, wire) for (_, tgt, wire) in self.dag.edges(gate_node)] self.assertEqual( - sorted(self.dag._multi_graph.out_edges(gate_node._node_id)), + sorted(gate_node_out_edges), sorted( [ - (gate_node._node_id, self.dag.output_map[self.qreg[0]]._node_id, self.qreg[0]), - (gate_node._node_id, self.dag.output_map[self.creg[0]]._node_id, self.creg[0]), + (self.dag.output_map[self.qreg[0]]._node_id, self.qreg[0]), + (self.dag.output_map[self.creg[0]]._node_id, self.creg[0]), ] ), ) diff --git a/test/python/transpiler/_dummy_passes.py b/test/python/transpiler/_dummy_passes.py index 64956e541024..eaddfe6d1ddd 100644 --- a/test/python/transpiler/_dummy_passes.py +++ b/test/python/transpiler/_dummy_passes.py @@ -122,10 +122,10 @@ class PassF_reduce_dag_property(DummyTP): def run(self, dag): super().run(dag) - if not hasattr(dag, "property"): - dag.property = 8 - dag.property = round(dag.property * 0.8) - logging.getLogger(logger).info("dag property = %i", dag.property) + if dag.duration is None: + dag.duration = 8 + dag.duration = round(dag.duration * 0.8) + logging.getLogger(logger).info("dag property = %i", dag.duration) return dag @@ -138,8 +138,8 @@ class PassG_calculates_dag_property(DummyAP): def run(self, dag): super().run(dag) - if hasattr(dag, "property"): - self.property_set["property"] = dag.property + if dag.duration is not None: + self.property_set["property"] = dag.duration else: self.property_set["property"] = 8 logging.getLogger(logger).info( diff --git a/test/python/transpiler/test_collect_multiq_blocks.py b/test/python/transpiler/test_collect_multiq_blocks.py index 58589d838e33..e2446d03da2a 100644 --- a/test/python/transpiler/test_collect_multiq_blocks.py +++ b/test/python/transpiler/test_collect_multiq_blocks.py @@ -93,6 +93,7 @@ def test_block_interrupted_by_gate(self): # but equivalent between python 3.5 and 3.7 # there is no implied topology in a block, so this isn't an issue dag_nodes = [set(dag_nodes[:4]), set(dag_nodes[4:])] + pass_nodes = [set(bl) for bl in pass_.property_set["block_list"]] self.assertEqual(dag_nodes, pass_nodes) diff --git a/test/python/visualization/test_utils.py b/test/python/visualization/test_utils.py index 1dca43b6beb2..1ef87994d001 100644 --- a/test/python/visualization/test_utils.py +++ b/test/python/visualization/test_utils.py @@ -48,18 +48,18 @@ def test_get_layered_instructions(self): (qregs, cregs, layered_ops) = _utils._get_layered_instructions(self.circuit) exp = [ - [("cx", (self.qr2[0], self.qr2[1]), ()), ("cx", (self.qr1[0], self.qr1[1]), ())], - [("measure", (self.qr2[0],), (self.cr2[0],))], - [("measure", (self.qr1[0],), (self.cr1[0],))], - [("cx", (self.qr2[1], self.qr2[0]), ()), ("cx", (self.qr1[1], self.qr1[0]), ())], - [("measure", (self.qr2[1],), (self.cr2[1],))], - [("measure", (self.qr1[1],), (self.cr1[1],))], + {("cx", (self.qr2[0], self.qr2[1]), ()), ("cx", (self.qr1[0], self.qr1[1]), ())}, + {("measure", (self.qr2[0],), (self.cr2[0],))}, + {("measure", (self.qr1[0],), (self.cr1[0],))}, + {("cx", (self.qr2[1], self.qr2[0]), ()), ("cx", (self.qr1[1], self.qr1[0]), ())}, + {("measure", (self.qr2[1],), (self.cr2[1],))}, + {("measure", (self.qr1[1],), (self.cr1[1],))}, ] self.assertEqual([self.qr1[0], self.qr1[1], self.qr2[0], self.qr2[1]], qregs) self.assertEqual([self.cr1[0], self.cr1[1], self.cr2[0], self.cr2[1]], cregs) self.assertEqual( - exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_reverse_bits(self): @@ -69,18 +69,18 @@ def test_get_layered_instructions_reverse_bits(self): ) exp = [ - [("cx", (self.qr2[0], self.qr2[1]), ()), ("cx", (self.qr1[0], self.qr1[1]), ())], - [("measure", (self.qr2[0],), (self.cr2[0],))], - [("measure", (self.qr1[0],), (self.cr1[0],)), ("cx", (self.qr2[1], self.qr2[0]), ())], - [("cx", (self.qr1[1], self.qr1[0]), ())], - [("measure", (self.qr2[1],), (self.cr2[1],))], - [("measure", (self.qr1[1],), (self.cr1[1],))], + {("cx", (self.qr2[0], self.qr2[1]), ()), ("cx", (self.qr1[0], self.qr1[1]), ())}, + {("measure", (self.qr2[0],), (self.cr2[0],))}, + {("measure", (self.qr1[0],), (self.cr1[0],)), ("cx", (self.qr2[1], self.qr2[0]), ())}, + {("cx", (self.qr1[1], self.qr1[0]), ())}, + {("measure", (self.qr2[1],), (self.cr2[1],))}, + {("measure", (self.qr1[1],), (self.cr1[1],))}, ] self.assertEqual([self.qr2[1], self.qr2[0], self.qr1[1], self.qr1[0]], qregs) self.assertEqual([self.cr2[1], self.cr2[0], self.cr1[1], self.cr1[0]], cregs) self.assertEqual( - exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_remove_idle_wires(self): @@ -103,18 +103,18 @@ def test_get_layered_instructions_remove_idle_wires(self): (qregs, cregs, layered_ops) = _utils._get_layered_instructions(circuit, idle_wires=False) exp = [ - [("cx", (qr2[0], qr2[1]), ()), ("cx", (qr1[0], qr1[1]), ())], - [("measure", (qr2[0],), (cr2[0],))], - [("measure", (qr1[0],), (cr1[0],))], - [("cx", (qr2[1], qr2[0]), ()), ("cx", (qr1[1], qr1[0]), ())], - [("measure", (qr2[1],), (cr2[1],))], - [("measure", (qr1[1],), (cr1[1],))], + {("cx", (qr2[0], qr2[1]), ()), ("cx", (qr1[0], qr1[1]), ())}, + {("measure", (qr2[0],), (cr2[0],))}, + {("measure", (qr1[0],), (cr1[0],))}, + {("cx", (qr2[1], qr2[0]), ()), ("cx", (qr1[1], qr1[0]), ())}, + {("measure", (qr2[1],), (cr2[1],))}, + {("measure", (qr1[1],), (cr1[1],))}, ] self.assertEqual([qr1[0], qr1[1], qr2[0], qr2[1]], qregs) self.assertEqual([cr1[0], cr1[1], cr2[0], cr2[1]], cregs) self.assertEqual( - exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_left_justification_simple(self): @@ -136,15 +136,15 @@ def test_get_layered_instructions_left_justification_simple(self): (_, _, layered_ops) = _utils._get_layered_instructions(qc, justify="left") l_exp = [ - [ + { ("h", (Qubit(QuantumRegister(4, "q"), 1),), ()), ("h", (Qubit(QuantumRegister(4, "q"), 2),), ()), - ], - [("cx", (Qubit(QuantumRegister(4, "q"), 0), Qubit(QuantumRegister(4, "q"), 3)), ())], + }, + {("cx", (Qubit(QuantumRegister(4, "q"), 0), Qubit(QuantumRegister(4, "q"), 3)), ())}, ] self.assertEqual( - l_exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + l_exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_right_justification_simple(self): @@ -166,15 +166,15 @@ def test_get_layered_instructions_right_justification_simple(self): (_, _, layered_ops) = _utils._get_layered_instructions(qc, justify="right") r_exp = [ - [("cx", (Qubit(QuantumRegister(4, "q"), 0), Qubit(QuantumRegister(4, "q"), 3)), ())], - [ + {("cx", (Qubit(QuantumRegister(4, "q"), 0), Qubit(QuantumRegister(4, "q"), 3)), ())}, + { ("h", (Qubit(QuantumRegister(4, "q"), 1),), ()), ("h", (Qubit(QuantumRegister(4, "q"), 2),), ()), - ], + }, ] self.assertEqual( - r_exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + r_exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_left_justification_less_simple(self): @@ -215,33 +215,33 @@ def test_get_layered_instructions_left_justification_less_simple(self): (_, _, layered_ops) = _utils._get_layered_instructions(qc, justify="left") l_exp = [ - [ + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], - [("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())], - [ + }, + {("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())}, + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], - [("u2", (Qubit(QuantumRegister(5, "q"), 1),), ())], - [ + }, + {("u2", (Qubit(QuantumRegister(5, "q"), 1),), ())}, + { ( "measure", (Qubit(QuantumRegister(5, "q"), 0),), (Clbit(ClassicalRegister(1, "c1"), 0),), ) - ], - [("u2", (Qubit(QuantumRegister(5, "q"), 0),), ())], - [("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())], - [ + }, + {("u2", (Qubit(QuantumRegister(5, "q"), 0),), ())}, + {("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())}, + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], + }, ] self.assertEqual( - l_exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + l_exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_right_justification_less_simple(self): @@ -282,35 +282,35 @@ def test_get_layered_instructions_right_justification_less_simple(self): (_, _, layered_ops) = _utils._get_layered_instructions(qc, justify="right") r_exp = [ - [ + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], - [("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())], - [ + }, + {("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())}, + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], - [ + }, + { ( "measure", (Qubit(QuantumRegister(5, "q"), 0),), (Clbit(ClassicalRegister(1, "c1"), 0),), ) - ], - [ + }, + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], - [("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())], - [ + }, + {("cx", (Qubit(QuantumRegister(5, "q"), 1), Qubit(QuantumRegister(5, "q"), 0)), ())}, + { ("u2", (Qubit(QuantumRegister(5, "q"), 0),), ()), ("u2", (Qubit(QuantumRegister(5, "q"), 1),), ()), - ], + }, ] self.assertEqual( - r_exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + r_exp, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) def test_get_layered_instructions_op_with_cargs(self): @@ -335,25 +335,25 @@ def test_get_layered_instructions_op_with_cargs(self): (_, _, layered_ops) = _utils._get_layered_instructions(qc) expected = [ - [("h", (Qubit(QuantumRegister(2, "q"), 0),), ())], - [ + {("h", (Qubit(QuantumRegister(2, "q"), 0),), ())}, + { ( "measure", (Qubit(QuantumRegister(2, "q"), 0),), (Clbit(ClassicalRegister(2, "c"), 0),), ) - ], - [ + }, + { ( "add_circ", (Qubit(QuantumRegister(2, "q"), 1),), (Clbit(ClassicalRegister(2, "c"), 0),), ) - ], + }, ] self.assertEqual( - expected, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops] + expected, [{(op.name, op.qargs, op.cargs) for op in ops} for ops in layered_ops] ) @unittest.skipUnless(optionals.HAS_PYLATEX, "needs pylatexenc") From 54ac8f17517759e5ae591fe36a73a5ee3ffda615 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Mon, 26 Aug 2024 09:35:41 +0200 Subject: [PATCH 22/85] Move the circuit library's entanglement logic to Rust (#12950) * Move ``get_entangler_map`` to Rust * add reno * add docs, better arg order * clippy * add docs to make reviewers happier * use Itertools::combinations thanks @alexanderivrii for the hint! * avoid usage of convert_idx * implement reviews * implement review comments * rm unused import --- .../src/circuit_library/entanglement.rs | 245 ++++++++++++++++++ crates/accelerate/src/circuit_library/mod.rs | 21 ++ crates/accelerate/src/lib.rs | 1 + crates/pyext/src/lib.rs | 17 +- qiskit/__init__.py | 1 + qiskit/circuit/library/n_local/n_local.py | 52 +--- ...ircular-entanglement-5aadd5adf75c0c13.yaml | 16 ++ test/python/circuit/library/test_nlocal.py | 157 ++++++++++- 8 files changed, 456 insertions(+), 54 deletions(-) create mode 100644 crates/accelerate/src/circuit_library/entanglement.rs create mode 100644 crates/accelerate/src/circuit_library/mod.rs create mode 100644 releasenotes/notes/fix-circular-entanglement-5aadd5adf75c0c13.yaml diff --git a/crates/accelerate/src/circuit_library/entanglement.rs b/crates/accelerate/src/circuit_library/entanglement.rs new file mode 100644 index 000000000000..db602ef717fa --- /dev/null +++ b/crates/accelerate/src/circuit_library/entanglement.rs @@ -0,0 +1,245 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use itertools::Itertools; +use pyo3::prelude::*; +use pyo3::{ + types::{PyAnyMethods, PyInt, PyList, PyListMethods, PyString, PyTuple}, + Bound, PyAny, PyResult, +}; + +use crate::QiskitError; + +/// Get all-to-all entanglement. For 4 qubits and block size 2 we have: +/// [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] +fn full(num_qubits: u32, block_size: u32) -> impl Iterator> { + (0..num_qubits).combinations(block_size as usize) +} + +/// Get a linear entanglement structure. For ``n`` qubits and block size ``m`` we have: +/// [(0..m-1), (1..m), (2..m+1), ..., (n-m..n-1)] +fn linear(num_qubits: u32, block_size: u32) -> impl DoubleEndedIterator> { + (0..num_qubits - block_size + 1) + .map(move |start_index| (start_index..start_index + block_size).collect()) +} + +/// Get a reversed linear entanglement. This is like linear entanglement but in reversed order: +/// [(n-m..n-1), ..., (1..m), (0..m-1)] +/// This is particularly interesting, as CX+"full" uses n(n-1)/2 gates, but operationally equals +/// CX+"reverse_linear", which needs only n-1 gates. +fn reverse_linear(num_qubits: u32, block_size: u32) -> impl Iterator> { + linear(num_qubits, block_size).rev() +} + +/// Return the qubit indices for circular entanglement. This is defined as tuples of length ``m`` +/// starting at each possible index ``(0..n)``. Historically, Qiskit starts with index ``n-m+1``. +/// This is probably easiest understood for a concerete example of 4 qubits and block size 3: +/// [(2,3,0), (3,0,1), (0,1,2), (1,2,3)] +fn circular(num_qubits: u32, block_size: u32) -> Box>> { + if block_size == 1 || num_qubits == block_size { + Box::new(linear(num_qubits, block_size)) + } else { + let historic_offset = num_qubits - block_size + 1; + Box::new((0..num_qubits).map(move |start_index| { + (0..block_size) + .map(|i| (historic_offset + start_index + i) % num_qubits) + .collect() + })) + } +} + +/// Get pairwise entanglement. This is typically used on 2 qubits and only has a depth of 2, as +/// first all odd pairs, and then even pairs are entangled. For example on 6 qubits: +/// [(0, 1), (2, 3), (4, 5), /* now the even pairs */ (1, 2), (3, 4)] +fn pairwise(num_qubits: u32) -> impl Iterator> { + // for Python-folks (like me): pairwise is equal to linear[::2] + linear[1::2] + linear(num_qubits, 2) + .step_by(2) + .chain(linear(num_qubits, 2).skip(1).step_by(2)) +} + +/// The shifted, circular, alternating (sca) entanglement is motivated from circuits 14/15 of +/// https://arxiv.org/abs/1905.10876. It corresponds to circular entanglement, with the difference +/// that in each layer (controlled by ``offset``) the entanglement gates are shifted by one, plus +/// in each second layer, the entanglement gate is turned upside down. +/// Offset 0 -> [(2,3,0), (3,0,1), (0,1,2), (1,2,3)] +/// Offset 1 -> [(3,2,1), (0,3,2), (1,0,3), (2,1,0)] +/// Offset 2 -> [(0,1,2), (1,2,3), (2,3,0), (3,0,1)] +/// ... +fn shift_circular_alternating( + num_qubits: u32, + block_size: u32, + offset: usize, +) -> Box>> { + // index at which we split the circular iterator -- we use Python-like indexing here, + // and define ``split`` as equivalent to a Python index of ``-offset`` + let split = (num_qubits - (offset as u32 % num_qubits)) % num_qubits; + let shifted = circular(num_qubits, block_size) + .skip(split as usize) + .chain(circular(num_qubits, block_size).take(split as usize)); + if offset % 2 == 0 { + Box::new(shifted) + } else { + // if the offset is odd, reverse the indices inside the qubit block (e.g. turn CX + // gates upside down) + Box::new(shifted.map(|indices| indices.into_iter().rev().collect())) + } +} + +/// Get an entangler map for an arbitrary number of qubits. +/// +/// Args: +/// num_qubits: The number of qubits of the circuit. +/// block_size: The number of qubits of the entangling block. +/// entanglement: The entanglement strategy as string. +/// offset: The block offset, can be used if the entanglements differ per block, +/// for example used in the "sca" mode. +/// +/// Returns: +/// The entangler map using mode ``entanglement`` to scatter a block of ``block_size`` +/// qubits on ``num_qubits`` qubits. +pub fn get_entanglement_from_str( + num_qubits: u32, + block_size: u32, + entanglement: &str, + offset: usize, +) -> PyResult>>> { + if num_qubits == 0 || block_size == 0 { + return Ok(Box::new(std::iter::empty())); + } + + if block_size > num_qubits { + return Err(QiskitError::new_err(format!( + "block_size ({}) cannot be larger than number of qubits ({})", + block_size, num_qubits + ))); + } + + match (entanglement, block_size) { + ("full", _) => Ok(Box::new(full(num_qubits, block_size))), + ("linear", _) => Ok(Box::new(linear(num_qubits, block_size))), + ("reverse_linear", _) => Ok(Box::new(reverse_linear(num_qubits, block_size))), + ("sca", _) => Ok(shift_circular_alternating(num_qubits, block_size, offset)), + ("circular", _) => Ok(circular(num_qubits, block_size)), + ("pairwise", 1) => Ok(Box::new(linear(num_qubits, 1))), + ("pairwise", 2) => Ok(Box::new(pairwise(num_qubits))), + ("pairwise", _) => Err(QiskitError::new_err(format!( + "block_size ({}) can be at most 2 for pairwise entanglement", + block_size + ))), + _ => Err(QiskitError::new_err(format!( + "Unsupported entanglement: {}", + entanglement + ))), + } +} + +/// Get an entangler map for an arbitrary number of qubits. +/// +/// Args: +/// num_qubits: The number of qubits of the circuit. +/// block_size: The number of qubits of the entangling block. +/// entanglement: The entanglement strategy. +/// offset: The block offset, can be used if the entanglements differ per block, +/// for example used in the "sca" mode. +/// +/// Returns: +/// The entangler map using mode ``entanglement`` to scatter a block of ``block_size`` +/// qubits on ``num_qubits`` qubits. +pub fn get_entanglement<'a>( + num_qubits: u32, + block_size: u32, + entanglement: &'a Bound, + offset: usize, +) -> PyResult>> + 'a>> { + // unwrap the callable, if it is one + let entanglement = if entanglement.is_callable() { + entanglement.call1((offset,))? + } else { + entanglement.to_owned() + }; + + if let Ok(strategy) = entanglement.downcast::() { + let as_str = strategy.to_string(); + return Ok(Box::new( + get_entanglement_from_str(num_qubits, block_size, as_str.as_str(), offset)?.map(Ok), + )); + } else if let Ok(list) = entanglement.downcast::() { + let entanglement_iter = list.iter().map(move |el| { + let connections = el + .downcast::()? + // .expect("Entanglement must be list of tuples") // clearer error message than `?` + .iter() + .map(|index| index.downcast::()?.extract()) + .collect::, _>>()?; + + if connections.len() != block_size as usize { + return Err(QiskitError::new_err(format!( + "Entanglement {:?} does not match block size {}", + connections, block_size + ))); + } + Ok(connections) + }); + return Ok(Box::new(entanglement_iter)); + } + Err(QiskitError::new_err( + "Entanglement must be a string or list of qubit indices.", + )) +} + +/// Get the entanglement for given number of qubits and block size. +/// +/// Args: +/// num_qubits: The number of qubits to entangle. +/// block_size: The entanglement block size (e.g. 2 for CX or 3 for CCX). +/// entanglement: The entanglement strategy. This can be one of: +/// +/// * string: Available options are ``"full"``, ``"linear"``, ``"pairwise"`` +/// ``"reverse_linear"``, ``"circular"``, or ``"sca"``. +/// * list of tuples: A list of entanglements given as tuple, e.g. [(0, 1), (1, 2)]. +/// * callable: A callable that takes as input an offset as ``int`` (usually the layer +/// in the variational circuit) and returns a string or list of tuples to use as +/// entanglement in this layer. +/// +/// offset: An offset used by certain entanglement strategies (e.g. ``"sca"``) or if the +/// entanglement is given as callable. This is typically used to have different +/// entanglement structures in different layers of variational quantum circuits. +/// +/// Returns: +/// The entanglement as list of tuples. +/// +/// Raises: +/// QiskitError: In case the entanglement is invalid. +#[pyfunction] +#[pyo3(signature = (num_qubits, block_size, entanglement, offset=0))] +pub fn get_entangler_map<'py>( + py: Python<'py>, + num_qubits: u32, + block_size: u32, + entanglement: &Bound, + offset: usize, +) -> PyResult>> { + // The entanglement is Result>>>, so there's two + // levels of errors we must handle: the outer error is handled by the outer match statement, + // and the inner (Result>) is handled upon the PyTuple creation. + match get_entanglement(num_qubits, block_size, entanglement, offset) { + Ok(entanglement) => entanglement + .into_iter() + .map(|vec| match vec { + Ok(vec) => Ok(PyTuple::new_bound(py, vec)), + Err(e) => Err(e), + }) + .collect::, _>>(), + Err(e) => Err(e), + } +} diff --git a/crates/accelerate/src/circuit_library/mod.rs b/crates/accelerate/src/circuit_library/mod.rs new file mode 100644 index 000000000000..d0444c484dc8 --- /dev/null +++ b/crates/accelerate/src/circuit_library/mod.rs @@ -0,0 +1,21 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use pyo3::prelude::*; + +mod entanglement; + +#[pymodule] +pub fn circuit_library(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(entanglement::get_entangler_map))?; + Ok(()) +} diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 4e079ea84b57..5414183d22cc 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -14,6 +14,7 @@ use std::env; use pyo3::import_exception; +pub mod circuit_library; pub mod convert_2q_block_matrix; pub mod dense_layout; pub mod edge_collections; diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 04b0c0609347..e8971bc87629 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -13,14 +13,14 @@ use pyo3::prelude::*; use qiskit_accelerate::{ - convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, - error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, - isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, - pauli_exp_val::pauli_expval, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, - sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, - stochastic_swap::stochastic_swap, synthesis::synthesis, target_transpiler::target, - two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, utils::utils, - vf2_layout::vf2_layout, + circuit_library::circuit_library, convert_2q_block_matrix::convert_2q_block_matrix, + dense_layout::dense_layout, error_map::error_map, + euler_one_qubit_decomposer::euler_one_qubit_decomposer, isometry::isometry, nlayout::nlayout, + optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, results::results, + sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, + star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, + target_transpiler::target, two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, + utils::utils, vf2_layout::vf2_layout, }; #[inline(always)] @@ -39,6 +39,7 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, qiskit_circuit::circuit, "circuit")?; add_submodule(m, qiskit_qasm2::qasm2, "qasm2")?; add_submodule(m, qiskit_qasm3::qasm3, "qasm3")?; + add_submodule(m, circuit_library, "circuit_library")?; add_submodule(m, convert_2q_block_matrix, "convert_2q_block_matrix")?; add_submodule(m, dense_layout, "dense_layout")?; add_submodule(m, error_map, "error_map")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 6a8df393307e..33933fd8fd7e 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -60,6 +60,7 @@ # We manually define them on import so people can directly import qiskit._accelerate.* submodules # and not have to rely on attribute access. No action needed for top-level extension packages. sys.modules["qiskit._accelerate.circuit"] = _accelerate.circuit +sys.modules["qiskit._accelerate.circuit_library"] = _accelerate.circuit_library sys.modules["qiskit._accelerate.convert_2q_block_matrix"] = _accelerate.convert_2q_block_matrix sys.modules["qiskit._accelerate.dense_layout"] = _accelerate.dense_layout sys.modules["qiskit._accelerate.error_map"] = _accelerate.error_map diff --git a/qiskit/circuit/library/n_local/n_local.py b/qiskit/circuit/library/n_local/n_local.py index 2a750195dab3..f948a458ad7b 100644 --- a/qiskit/circuit/library/n_local/n_local.py +++ b/qiskit/circuit/library/n_local/n_local.py @@ -31,9 +31,11 @@ ) from qiskit.exceptions import QiskitError from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping +from qiskit._accelerate.circuit_library import get_entangler_map as fast_entangler_map from ..blueprintcircuit import BlueprintCircuit + if typing.TYPE_CHECKING: import qiskit # pylint: disable=cyclic-import @@ -1037,51 +1039,11 @@ def get_entangler_map( Raises: ValueError: If the entanglement mode ist not supported. """ - n, m = num_circuit_qubits, num_block_qubits - if m > n: - raise ValueError( - "The number of block qubits must be smaller or equal to the number of " - "qubits in the circuit." - ) - - if entanglement == "pairwise" and num_block_qubits > 2: - raise ValueError("Pairwise entanglement is not defined for blocks with more than 2 qubits.") - - if entanglement == "full": - return list(itertools.combinations(list(range(n)), m)) - elif entanglement == "reverse_linear": - # reverse linear connectivity. In the case of m=2 and the entanglement_block='cx' - # then it's equivalent to 'full' entanglement - reverse = [tuple(range(n - i - m, n - i)) for i in range(n - m + 1)] - return reverse - elif entanglement in ["linear", "circular", "sca", "pairwise"]: - linear = [tuple(range(i, i + m)) for i in range(n - m + 1)] - # if the number of block qubits is 1, we don't have to add the 'circular' part - if entanglement == "linear" or m == 1: - return linear - - if entanglement == "pairwise": - return linear[::2] + linear[1::2] - - # circular equals linear plus top-bottom entanglement (if there's space for it) - if n > m: - circular = [tuple(range(n - m + 1, n)) + (0,)] + linear - else: - circular = linear - if entanglement == "circular": - return circular - - # sca is circular plus shift and reverse - shifted = circular[-offset:] + circular[:-offset] - if offset % 2 == 1: # if odd, reverse the qubit indices - sca = [ind[::-1] for ind in shifted] - else: - sca = shifted - - return sca - - else: - raise ValueError(f"Unsupported entanglement type: {entanglement}") + try: + return fast_entangler_map(num_circuit_qubits, num_block_qubits, entanglement, offset) + except Exception as exc: + # need this as Rust is now raising a QiskitError, where this function was raising ValueError + raise ValueError("Something went wrong in Rust space, here's the error:") from exc _StdlibGateResult = collections.namedtuple("_StdlibGateResult", ("gate", "num_params")) diff --git a/releasenotes/notes/fix-circular-entanglement-5aadd5adf75c0c13.yaml b/releasenotes/notes/fix-circular-entanglement-5aadd5adf75c0c13.yaml new file mode 100644 index 000000000000..fbede3d31756 --- /dev/null +++ b/releasenotes/notes/fix-circular-entanglement-5aadd5adf75c0c13.yaml @@ -0,0 +1,16 @@ +fixes: + - | + Fixed a bug with the ``"circular"`` and ``"sca"`` entanglement for + :class:`.NLocal` circuits and its derivatives. For entanglement blocks + of more than 2 qubits, the circular entanglement was previously missing + some connections. For example, for 4 qubits and a block size of 3 the + code previously used:: + + [(2, 3, 0), (0, 1, 2), (1, 2, 3)] + + but now is correctly adding the ``(3, 0, 1)`` connections, that is:: + + [(2, 3, 0), (3, 0, 1), (0, 1, 2), (1, 2, 3)] + + As such, the ``"circular"`` and ``"sca"`` entanglements use ``num_qubits`` + entangling blocks per layer. diff --git a/test/python/circuit/library/test_nlocal.py b/test/python/circuit/library/test_nlocal.py index 2e308af48ff4..dd39aa61ba61 100644 --- a/test/python/circuit/library/test_nlocal.py +++ b/test/python/circuit/library/test_nlocal.py @@ -42,6 +42,10 @@ from qiskit.circuit.random.utils import random_circuit from qiskit.converters.circuit_to_dag import circuit_to_dag from qiskit.quantum_info import Operator +from qiskit.exceptions import QiskitError + +from qiskit._accelerate.circuit_library import get_entangler_map as fast_entangler_map + from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -339,7 +343,7 @@ def get_expected_entangler_map(rep_num, mode): (2, 3, 4), ] else: - circular = [(3, 4, 0), (0, 1, 2), (1, 2, 3), (2, 3, 4)] + circular = [(3, 4, 0), (4, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 4)] if mode == "circular": return circular sca = circular[-rep_num:] + circular[:-rep_num] @@ -928,5 +932,156 @@ def test_full_vs_reverse_linear(self, num_qubits): self.assertEqual(Operator(full), Operator(reverse)) +@ddt +class TestEntanglement(QiskitTestCase): + """Test getting the entanglement structure.""" + + @data( + ("linear", [(0, 1), (1, 2), (2, 3)]), + ("reverse_linear", [(2, 3), (1, 2), (0, 1)]), + ("pairwise", [(0, 1), (2, 3), (1, 2)]), + ("circular", [(3, 0), (0, 1), (1, 2), (2, 3)]), + ("full", [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]), + ) + @unpack + def test_2q_str(self, strategy, expected): + """Test getting by string.""" + entanglement = fast_entangler_map( + num_qubits=4, block_size=2, entanglement=strategy, offset=0 + ) + self.assertEqual(expected, entanglement) + + @data( + ("linear", [(0, 1, 2), (1, 2, 3)]), + ("reverse_linear", [(1, 2, 3), (0, 1, 2)]), + ("circular", [(2, 3, 0), (3, 0, 1), (0, 1, 2), (1, 2, 3)]), + ("full", [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]), + ) + @unpack + def test_3q_str(self, strategy, expected): + """Test getting by string.""" + entanglement = fast_entangler_map( + num_qubits=4, block_size=3, entanglement=strategy, offset=0 + ) + self.assertEqual(expected, entanglement) + + def test_2q_sca(self): + """Test shift, circular, alternating on 2-qubit blocks.""" + expected = { # offset: result + 0: [(3, 0), (0, 1), (1, 2), (2, 3)], + 1: [(3, 2), (0, 3), (1, 0), (2, 1)], + 2: [(1, 2), (2, 3), (3, 0), (0, 1)], + 3: [(1, 0), (2, 1), (3, 2), (0, 3)], + } + for offset in range(8): + with self.subTest(offset=offset): + entanglement = fast_entangler_map( + num_qubits=4, block_size=2, entanglement="sca", offset=offset + ) + self.assertEqual(expected[offset % 4], entanglement) + + def test_3q_sca(self): + """Test shift, circular, alternating on 3-qubit blocks.""" + circular = [(2, 3, 0), (3, 0, 1), (0, 1, 2), (1, 2, 3)] + for offset in range(8): + expected = circular[-(offset % 4) :] + circular[: -(offset % 4)] + if offset % 2 == 1: + expected = [tuple(reversed(indices)) for indices in expected] + with self.subTest(offset=offset): + entanglement = fast_entangler_map( + num_qubits=4, block_size=3, entanglement="sca", offset=offset + ) + self.assertEqual(expected, entanglement) + + @data("full", "reverse_linear", "linear", "circular", "sca", "pairwise") + def test_0q(self, entanglement): + """Test the corner case of a single qubit block.""" + entanglement = fast_entangler_map( + num_qubits=3, block_size=0, entanglement=entanglement, offset=0 + ) + expect = [] + self.assertEqual(entanglement, expect) + + @data("full", "reverse_linear", "linear", "circular", "sca", "pairwise") + def test_1q(self, entanglement): + """Test the corner case of a single qubit block.""" + entanglement = fast_entangler_map( + num_qubits=3, block_size=1, entanglement=entanglement, offset=0 + ) + expect = [(i,) for i in range(3)] + + self.assertEqual(set(entanglement), set(expect)) # order does not matter for 1 qubit + + @data("full", "reverse_linear", "linear", "circular", "sca") + def test_full_block(self, entanglement): + """Test the corner case of the block size equal the number of qubits.""" + entanglement = fast_entangler_map( + num_qubits=5, block_size=5, entanglement=entanglement, offset=0 + ) + expect = [tuple(range(5))] + + self.assertEqual(entanglement, expect) + + def test_pairwise_limit(self): + """Test pairwise raises an error above 2 qubits.""" + _ = fast_entangler_map(num_qubits=4, block_size=1, entanglement="pairwise", offset=0) + _ = fast_entangler_map(num_qubits=4, block_size=2, entanglement="pairwise", offset=0) + with self.assertRaises(QiskitError): + _ = fast_entangler_map(num_qubits=4, block_size=3, entanglement="pairwise", offset=0) + + def test_invalid_blocksize(self): + """Test the block size being too large.""" + with self.assertRaises(QiskitError): + _ = fast_entangler_map(num_qubits=2, block_size=3, entanglement="linear", offset=0) + + def test_invalid_entanglement_str(self): + """Test invalid entanglement string.""" + with self.assertRaises(QiskitError): + _ = fast_entangler_map(num_qubits=4, block_size=2, entanglement="lniaer", offset=0) + + def test_as_list(self): + """Test passing a list just returns the list.""" + expected = [(0, 1), (1, 10), (2, 10)] + out = fast_entangler_map(num_qubits=20, block_size=2, entanglement=expected, offset=0) + self.assertEqual(expected, out) + + def test_invalid_list(self): + """Test passing a list that does not match the block size.""" + + # TODO this test fails, somehow the error is not propagated correctly! + expected = [(0, 1), (1, 2, 10)] + with self.assertRaises(QiskitError): + _ = fast_entangler_map(num_qubits=20, block_size=2, entanglement=expected, offset=0) + + def test_callable_list(self): + """Test using a callable.""" + + def my_entanglement(offset): + return [(0, 1)] if offset % 2 == 0 else [(1, 2)] + + for offset in range(3): + with self.subTest(offset=offset): + expect = my_entanglement(offset) + result = fast_entangler_map( + num_qubits=3, block_size=2, entanglement=my_entanglement, offset=offset + ) + self.assertEqual(expect, result) + + def test_callable_str(self): + """Test using a callable.""" + + def my_entanglement(offset): + return "linear" if offset % 2 == 0 else "pairwise" + + expected = {"linear": [(0, 1), (1, 2), (2, 3)], "pairwise": [(0, 1), (2, 3), (1, 2)]} + + for offset in range(3): + with self.subTest(offset=offset): + result = fast_entangler_map( + num_qubits=4, block_size=2, entanglement=my_entanglement, offset=offset + ) + self.assertEqual(expected["linear" if offset % 2 == 0 else "pairwise"], result) + + if __name__ == "__main__": unittest.main() From 83ecf39656f41dfca811ae73d4d4292d0b935338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Dao?= <100034085+timmintam@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:17:49 +0200 Subject: [PATCH 23/85] Fix `UnitaryGate.repeat()` method (#12986) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: deal with special case for `UnitaryGate` * add test * add release note * typo * generalize the fix to other gates * fix seeds * update unittests * Add missing unittests --------- Co-authored-by: Luciano Bello Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- qiskit/circuit/gate.py | 5 ++++- .../notes/fix_11990-8551c7250207fc76.yaml | 6 ++++++ .../circuit/library/test_linear_function.py | 13 +++++++++++++ test/python/circuit/library/test_permutation.py | 6 ++++++ test/python/circuit/test_diagonal_gate.py | 13 +++++++++++++ test/python/circuit/test_gate_definitions.py | 14 ++++++++++++++ test/python/circuit/test_hamiltonian_gate.py | 6 ++++++ test/python/circuit/test_initializer.py | 10 ++++++++++ test/python/circuit/test_isometry.py | 15 +++++++++++++++ test/python/circuit/test_uc.py | 7 +++++++ test/python/circuit/test_unitary.py | 5 +++++ 11 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix_11990-8551c7250207fc76.yaml diff --git a/qiskit/circuit/gate.py b/qiskit/circuit/gate.py index 37fd19e2022a..2f1c09668252 100644 --- a/qiskit/circuit/gate.py +++ b/qiskit/circuit/gate.py @@ -97,7 +97,10 @@ def __pow__(self, exponent: float) -> "Gate": return self.power(exponent) def _return_repeat(self, exponent: float) -> "Gate": - return Gate(name=f"{self.name}*{exponent}", num_qubits=self.num_qubits, params=self.params) + gate = Gate(name=f"{self.name}*{exponent}", num_qubits=self.num_qubits, params=[]) + gate.validate_parameter = self.validate_parameter + gate.params = self.params + return gate def control( self, diff --git a/releasenotes/notes/fix_11990-8551c7250207fc76.yaml b/releasenotes/notes/fix_11990-8551c7250207fc76.yaml new file mode 100644 index 000000000000..68912403cd39 --- /dev/null +++ b/releasenotes/notes/fix_11990-8551c7250207fc76.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes an error when calling the method :meth:`.UnitaryGate.repeat`. + Refer to `#11990 `_ for more + details. \ No newline at end of file diff --git a/test/python/circuit/library/test_linear_function.py b/test/python/circuit/library/test_linear_function.py index a3df1e9664a2..b7756faa7aa7 100644 --- a/test/python/circuit/library/test_linear_function.py +++ b/test/python/circuit/library/test_linear_function.py @@ -502,6 +502,19 @@ def test_clifford_linear_function_equivalence(self, num_qubits): self.assertEqual(Clifford(qc_to_linear_function), qc_to_clifford) self.assertEqual(qc_to_linear_function, LinearFunction(qc_to_clifford)) + @data(2, 3) + def test_repeat_method(self, num_qubits): + """Test the repeat() method.""" + rng = np.random.default_rng(127) + for num_gates, seed in zip( + [0, 5, 5 * num_qubits], rng.integers(100000, size=10, dtype=np.uint64) + ): + # create a random linear circuit + linear_circuit = random_linear_circuit(num_qubits, num_gates, seed=seed) + operator = Operator(linear_circuit) + linear_function = LinearFunction(linear_circuit) + self.assertTrue(Operator(linear_function.repeat(2)), operator @ operator) + if __name__ == "__main__": unittest.main() diff --git a/test/python/circuit/library/test_permutation.py b/test/python/circuit/library/test_permutation.py index 30d504d7dc8f..a2ec59431fe3 100644 --- a/test/python/circuit/library/test_permutation.py +++ b/test/python/circuit/library/test_permutation.py @@ -104,6 +104,12 @@ def test_inverse(self): expected_inverse_perm = PermutationGate([3, 0, 5, 1, 4, 2]) self.assertTrue(np.array_equal(inverse_perm.pattern, expected_inverse_perm.pattern)) + def test_repeat(self): + """Test the ``repeat`` method.""" + pattern = [2, 4, 1, 3, 0] + perm = PermutationGate(pattern) + self.assertTrue(np.allclose(Operator(perm.repeat(2)), Operator(perm) @ Operator(perm))) + class TestPermutationGatesOnCircuit(QiskitTestCase): """Tests for quantum circuits containing permutations.""" diff --git a/test/python/circuit/test_diagonal_gate.py b/test/python/circuit/test_diagonal_gate.py index de8d53e12d3b..bb9259999576 100644 --- a/test/python/circuit/test_diagonal_gate.py +++ b/test/python/circuit/test_diagonal_gate.py @@ -83,6 +83,19 @@ def test_npcomplex_params_conversion(self): all(isinstance(p, complex) and not isinstance(p, np.number) for p in params) ) + def test_repeat(self): + """Test the repeat() method.""" + for phases in [ + [0, 0], + np.array([0, 0.8, 1, 0]), + (2 * np.pi * np.random.rand(2**3)).tolist(), + ]: + with self.subTest(phases=phases): + diag = [np.exp(1j * ph) for ph in phases] + gate = DiagonalGate(diag) + operator = Operator(gate) + self.assertTrue(np.allclose(Operator(gate.repeat(2)), operator @ operator)) + def _get_diag_gate_matrix(diag): return np.diagflat(diag) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 950b0c478ed8..914ac8bab985 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -54,6 +54,8 @@ CZGate, RYYGate, PhaseGate, + PauliGate, + UCPauliRotGate, CPhaseGate, UGate, CUGate, @@ -184,6 +186,18 @@ def test_xx_minus_yy_definition(self): self.assertTrue(len(decomposed_circuit) > len(circuit)) self.assertTrue(Operator(circuit).equiv(Operator(decomposed_circuit), atol=1e-7)) + def test_pauligate_repeat(self): + """Test `repeat` method for `PauliGate`.""" + gate = PauliGate("XYZ") + operator = Operator(gate) + self.assertTrue(np.allclose(Operator(gate.repeat(2)), operator @ operator)) + + def test_ucpaulirotgate_repeat(self): + """Test `repeat` method for `UCPauliRotGate`.""" + gate = UCPauliRotGate([0.3, 0.5], "X") + operator = Operator(gate) + self.assertTrue(np.allclose(Operator(gate.repeat(2)), operator @ operator)) + @ddt class TestStandardGates(QiskitTestCase): diff --git a/test/python/circuit/test_hamiltonian_gate.py b/test/python/circuit/test_hamiltonian_gate.py index 60fb1e9a90a9..e65e2f07ba5e 100644 --- a/test/python/circuit/test_hamiltonian_gate.py +++ b/test/python/circuit/test_hamiltonian_gate.py @@ -62,6 +62,12 @@ def test_adjoint(self): ham.adjoint().to_matrix(), np.transpose(np.conj(ham.to_matrix())) ) + def test_repeat(self): + """test repeat operation""" + ham = HamiltonianGate(np.array([[1, 0.5 + 4j], [0.5 - 4j, -0.2]]), np.pi * 0.143) + operator = Operator(ham) + self.assertTrue(np.allclose(Operator(ham.repeat(2)), operator @ operator)) + class TestHamiltonianCircuit(QiskitTestCase): """Hamiltonian gate circuit tests.""" diff --git a/test/python/circuit/test_initializer.py b/test/python/circuit/test_initializer.py index 2507fbc6c139..990df5755d59 100644 --- a/test/python/circuit/test_initializer.py +++ b/test/python/circuit/test_initializer.py @@ -473,6 +473,16 @@ def test_gates_to_uncompute(self): vec = Statevector(qc) self.assertTrue(vec == Statevector(desired_vector)) + def test_repeat(self): + """Test the repeat() method.""" + desired_vector = np.array([0.5, 0.5, 0.5, 0.5]) + initialize = Initialize(desired_vector) + qr = QuantumRegister(2) + qc = QuantumCircuit(qr) + qc.append(initialize.repeat(2), qr) + statevector = Statevector(qc) + self.assertTrue(np.allclose(statevector, desired_vector)) + class TestInstructionParam(QiskitTestCase): """Test conversion of numpy type parameters.""" diff --git a/test/python/circuit/test_isometry.py b/test/python/circuit/test_isometry.py index 35ff639cedd5..ff497c76f48a 100644 --- a/test/python/circuit/test_isometry.py +++ b/test/python/circuit/test_isometry.py @@ -133,6 +133,21 @@ def test_isometry_inverse(self, iso): result = Operator(qc) np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0])) + @data( + np.eye(2, 2), + random_unitary(2, seed=297102).data, + np.eye(4, 4), + random_unitary(4, seed=123642).data, + random_unitary(8, seed=568288).data, + ) + def test_isometry_repeat(self, iso): + """Tests for the repeat of isometries from n to n qubits""" + iso_gate = Isometry(iso, 0, 0) + + op = Operator(iso_gate) + op_double = Operator(iso_gate.repeat(2)) + np.testing.assert_array_almost_equal(op @ op, op_double) + if __name__ == "__main__": unittest.main() diff --git a/test/python/circuit/test_uc.py b/test/python/circuit/test_uc.py index 87541d349c3f..0277c4afb43d 100644 --- a/test/python/circuit/test_uc.py +++ b/test/python/circuit/test_uc.py @@ -100,6 +100,13 @@ def test_inverse_ucg(self): self.assertTrue(np.allclose(unitary_desired, unitary)) + def test_repeat(self): + """test repeat operation""" + gates = [random_unitary(2, seed=seed).data for seed in [124435, 876345, 687462, 928365]] + + uc = UCGate(gates, up_to_diagonal=False) + self.assertTrue(np.allclose(Operator(uc.repeat(2)), Operator(uc) @ Operator(uc))) + def _get_ucg_matrix(squs): return block_diag(*squs) diff --git a/test/python/circuit/test_unitary.py b/test/python/circuit/test_unitary.py index 63edbdaffbf9..6ab4a93c3f7d 100644 --- a/test/python/circuit/test_unitary.py +++ b/test/python/circuit/test_unitary.py @@ -67,6 +67,11 @@ def test_adjoint(self): uni = UnitaryGate([[0, 1j], [-1j, 0]]) self.assertTrue(numpy.array_equal(uni.adjoint().to_matrix(), uni.to_matrix())) + def test_repeat(self): + """test repeat operation""" + uni = UnitaryGate([[1, 0], [0, 1j]]) + self.assertTrue(numpy.array_equal(Operator(uni.repeat(2)), Operator(uni) @ Operator(uni))) + class TestUnitaryCircuit(QiskitTestCase): """Matrix gate circuit tests.""" From f537602b8d69c38b4182390ed195899401b4efc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:06:08 -0400 Subject: [PATCH 24/85] Bump faer from 0.19.1 to 0.19.2 (#13037) Bumps [faer](https://github.com/sarah-ek/faer-rs) from 0.19.1 to 0.19.2. - [Changelog](https://github.com/sarah-ek/faer-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/sarah-ek/faer-rs/commits) --- updated-dependencies: - dependency-name: faer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 62 ++++++++++++++++++++++++------------ crates/accelerate/Cargo.toml | 2 +- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12daf2e6299e..394e03f5d122 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -276,7 +276,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -285,7 +285,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" dependencies = [ - "equator-macro", + "equator-macro 0.2.1", +] + +[[package]] +name = "equator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5099e7b6f0b7431c7a1c49f75929e2777693da192784f167066977a2965767af" +dependencies = [ + "equator-macro 0.4.1", ] [[package]] @@ -296,7 +305,18 @@ checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", +] + +[[package]] +name = "equator-macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5322a90066ddae2b705096eb9e10c465c0498ae93bf9bdd6437415327c88e3bb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", ] [[package]] @@ -307,15 +327,15 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "faer" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41543c4de4bfb32efdffdd75cbcca5ef41b800e8a811ea4a41fb9393c6ef3bc0" +checksum = "fe8894ad9275f1fd708e2f114f4059e80057ad3cc150b77a3f8a7991dd47ab37" dependencies = [ "bytemuck", "coe-rs", "dbgf", "dyn-stack", - "equator", + "equator 0.4.1", "faer-entity", "gemm", "libm", @@ -335,9 +355,9 @@ dependencies = [ [[package]] name = "faer-entity" -version = "0.19.0" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab968a02be27be95de0f1ad0af901b865fa0866b6a9b553a6cc9cf7f19c2ce71" +checksum = "c9c752ab2bff6f0b9597c6a1adc0112f7fd41fb343bc5a009a6274ae9d32fd03" dependencies = [ "bytemuck", "coe-rs", @@ -693,7 +713,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f563548d38f390ef9893e4883ec38c1fb312f569e98d76bededdd91a3b41a043" dependencies = [ - "equator", + "equator 0.2.2", "nano-gemm-c32", "nano-gemm-c64", "nano-gemm-codegen", @@ -970,7 +990,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -1043,9 +1063,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1071,7 +1091,7 @@ checksum = "d315b3197b780e4873bc0e11251cb56a33f65a6032a3d39b8d1405c255513766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -1139,7 +1159,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -1152,7 +1172,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -1457,7 +1477,7 @@ checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -1499,9 +1519,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -1551,7 +1571,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] [[package]] @@ -1847,5 +1867,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.76", ] diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index 838fc0153577..3248e61e29ac 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -20,7 +20,7 @@ num-traits = "0.2" num-complex.workspace = true rustworkx-core.workspace = true num-bigint.workspace = true -faer = "0.19.1" +faer = "0.19.2" itertools.workspace = true qiskit-circuit.workspace = true thiserror.workspace = true From cc87318f91fbe828ffc09f4d8865ff76af234b90 Mon Sep 17 00:00:00 2001 From: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:38:24 -0400 Subject: [PATCH 25/85] Expose `CircuitData` interners and registers to the `qiskit-circuit` crate (#13006) * Initial: Expose `CircuitData` interners and registers to the `qiskit-circuit` crate. - Make the `CircuitData` iter method be an exact-size iterator. * FIx: Expose immutable views of interners, registers and global phase. - Revert the changes making the interners and registers visible to the crate `qiskit-circuit`. - Create methods to expose immutable borrowed views of the interners, registers and global_phase to prevent from mutating the DAGCircuit. - Add `get_qargs` and `get_cargs` to unpack interned qargs ans cargs. - Other tweaks and fixes. * Format: Fix typo in comment Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> * Refactor: Use naming convention for getters. * Docs: Apply suggestions from code review - Correct incorrect docstrings for `qubits()` and `clbits()` Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> --------- Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> --- crates/circuit/src/circuit_data.rs | 45 ++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 4dd3956bee6a..5d3c5aba1877 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -16,7 +16,7 @@ use std::cell::OnceCell; use crate::bit_data::BitData; use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; use crate::imports::{ANNOTATED_OPERATION, CLBIT, QUANTUM_CIRCUIT, QUBIT}; -use crate::interner::{IndexedInterner, Interner}; +use crate::interner::{Index, IndexedInterner, Interner}; use crate::operations::{Operation, OperationRef, Param, StandardGate}; use crate::packed_instruction::{PackedInstruction, PackedOperation}; use crate::parameter_table::{ParameterTable, ParameterTableError, ParameterUse, ParameterUuid}; @@ -399,8 +399,8 @@ impl CircuitData { /// /// Returns: /// list(:class:`.Qubit`): The current sequence of registered qubits. - #[getter] - pub fn qubits(&self, py: Python<'_>) -> Py { + #[getter("qubits")] + pub fn py_qubits(&self, py: Python<'_>) -> Py { self.qubits.cached().clone_ref(py) } @@ -424,8 +424,8 @@ impl CircuitData { /// /// Returns: /// list(:class:`.Clbit`): The current sequence of registered clbits. - #[getter] - pub fn clbits(&self, py: Python<'_>) -> Py { + #[getter("clbits")] + pub fn py_clbits(&self, py: Python<'_>) -> Py { self.clbits.cached().clone_ref(py) } @@ -1137,6 +1137,41 @@ impl CircuitData { self.data.iter() } + /// Returns an immutable view of the Interner used for Qargs + pub fn qargs_interner(&self) -> &IndexedInterner> { + &self.qargs_interner + } + + /// Returns an immutable view of the Interner used for Cargs + pub fn cargs_interner(&self) -> &IndexedInterner> { + &self.cargs_interner + } + + /// Returns an immutable view of the Global Phase `Param` of the circuit + pub fn global_phase(&self) -> &Param { + &self.global_phase + } + + /// Returns an immutable view of the Qubits registered in the circuit + pub fn qubits(&self) -> &BitData { + &self.qubits + } + + /// Returns an immutable view of the Classical bits registered in the circuit + pub fn clbits(&self) -> &BitData { + &self.clbits + } + + /// Unpacks from InternerIndex to `[Qubit]` + pub fn get_qargs(&self, index: Index) -> &[Qubit] { + self.qargs_interner().intern(index) + } + + /// Unpacks from InternerIndex to `[Clbit]` + pub fn get_cargs(&self, index: Index) -> &[Clbit] { + self.cargs_interner().intern(index) + } + fn assign_parameters_inner(&mut self, py: Python, iter: I) -> PyResult<()> where I: IntoIterator, Param, HashSet)>, From 7b2d50cb9d89adc1f252102347090c511466a3d1 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 27 Aug 2024 14:08:33 +0100 Subject: [PATCH 26/85] Move interners from trait to generic structs (#13033) * Move interners from trait to generic structs This rewrites the interner mechanisms be defined in terms of two generic structs (`Interner` and `Interned`) that formalise the idea that the interned values are owned versions of a given reference type, and move the logically separate intern-related actions (get a key from the value, and get the value from the key) into separate functions (`get` and `insert`, respectively). This has a few advantages: 1. we now have both `insert` and `insert_owned` methods, which was awkward to add within the trait-based structure. This allows a more efficient path when the owned variant has already necessarily been constructed. 2. additionally, the standard `insert` path now takes only a reference type. For large circuits, most intern lookups will, in general, find a pre-existing key, so in situations where the interned value is sufficiently small that it can be within a static allocation (which is the case for almost all `qargs` and `cargs`), it's more efficient not to construct the owned type on the heap. 3. the type of the values retrieved from an interner are no longer indirected through the owned type that's stored. For example, where `IndexedInterner>` gave out `&Vec`s as its lookups, `Interner<[Qubit]>` returns the more standard `&[Qubit]`, which is only singly indirect rather than double. The following replacements are made: 1. The `IndexedInterner` struct from before is now just called `Interner` (and internally, it uses an `IndexSet` rather than manually tracking the indices). Its generic type is related to the references it returns, rather than the owned value it stores, so `IndexedInterner>` becomes `Interner<[Qubit]>`. 2. The `Interner` trait is now gone. Everything is just accessed as concrete methods on the `Interner` struct. 3. `<&IndexedInterner as Interner>::intern` (lookup of the value from an interner key) is now called `Interner::get`. 4. `<&mut IndexedInterner as Interner>::intern` (conversion of an owned value to an interner key) is now called `Interner::insert_owned`. 5. A new method, `Interner::insert`, can now be used when one need not have an owned allocation of the storage type; the correct value will be allocated if required (which is expected to be less frequent). 6. The intern key is no longer called `interner::Index`, but `Interned`, where the generic parameter `T` matches the generic of the `Interner` that gave out the key. * Improve internal documentation * Match names of interners between `CircuitData` and` DAGCircuit` --- crates/circuit/src/circuit_data.rs | 70 +++++---- crates/circuit/src/dag_circuit.rs | 162 ++++++++++---------- crates/circuit/src/interner.rs | 181 ++++++++++++++++------- crates/circuit/src/packed_instruction.rs | 6 +- 4 files changed, 242 insertions(+), 177 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 5d3c5aba1877..640eb22b9401 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -16,7 +16,7 @@ use std::cell::OnceCell; use crate::bit_data::BitData; use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; use crate::imports::{ANNOTATED_OPERATION, CLBIT, QUANTUM_CIRCUIT, QUBIT}; -use crate::interner::{Index, IndexedInterner, Interner}; +use crate::interner::{Interned, Interner}; use crate::operations::{Operation, OperationRef, Param, StandardGate}; use crate::packed_instruction::{PackedInstruction, PackedOperation}; use crate::parameter_table::{ParameterTable, ParameterTableError, ParameterUse, ParameterUuid}; @@ -91,9 +91,9 @@ pub struct CircuitData { /// The packed instruction listing. data: Vec, /// The cache used to intern instruction bits. - qargs_interner: IndexedInterner>, + qargs_interner: Interner<[Qubit]>, /// The cache used to intern instruction bits. - cargs_interner: IndexedInterner>, + cargs_interner: Interner<[Clbit]>, /// Qubits registered in the circuit. qubits: BitData, /// Clbits registered in the circuit. @@ -148,8 +148,8 @@ impl CircuitData { global_phase, )?; for (operation, params, qargs, cargs) in instruction_iter { - let qubits = (&mut res.qargs_interner).intern(qargs)?; - let clbits = (&mut res.cargs_interner).intern(cargs)?; + let qubits = res.qargs_interner.insert_owned(qargs); + let clbits = res.cargs_interner.insert_owned(cargs); let params = (!params.is_empty()).then(|| Box::new(params)); res.data.push(PackedInstruction { op: operation, @@ -199,9 +199,9 @@ impl CircuitData { instruction_iter.size_hint().0, global_phase, )?; - let no_clbit_index = (&mut res.cargs_interner).intern(Vec::new())?; + let no_clbit_index = res.cargs_interner.insert(&[]); for (operation, params, qargs) in instruction_iter { - let qubits = (&mut res.qargs_interner).intern(qargs.to_vec())?; + let qubits = res.qargs_interner.insert(&qargs); let params = (!params.is_empty()).then(|| Box::new(params)); res.data.push(PackedInstruction { op: operation.into(), @@ -227,8 +227,8 @@ impl CircuitData { ) -> PyResult { let mut res = CircuitData { data: Vec::with_capacity(instruction_capacity), - qargs_interner: IndexedInterner::new(), - cargs_interner: IndexedInterner::new(), + qargs_interner: Interner::new(), + cargs_interner: Interner::new(), qubits: BitData::new(py, "qubits".to_string()), clbits: BitData::new(py, "clbits".to_string()), param_table: ParameterTable::new(), @@ -258,9 +258,9 @@ impl CircuitData { params: &[Param], qargs: &[Qubit], ) -> PyResult<()> { - let no_clbit_index = (&mut self.cargs_interner).intern(Vec::new())?; + let no_clbit_index = self.cargs_interner.insert(&[]); let params = (!params.is_empty()).then(|| Box::new(params.iter().cloned().collect())); - let qubits = (&mut self.qargs_interner).intern(qargs.to_vec())?; + let qubits = self.qargs_interner.insert(qargs); self.data.push(PackedInstruction { op: operation.into(), qubits, @@ -351,8 +351,8 @@ impl CircuitData { ) -> PyResult { let mut self_ = CircuitData { data: Vec::new(), - qargs_interner: IndexedInterner::new(), - cargs_interner: IndexedInterner::new(), + qargs_interner: Interner::new(), + cargs_interner: Interner::new(), qubits: BitData::new(py, "qubits".to_string()), clbits: BitData::new(py, "clbits".to_string()), param_table: ParameterTable::new(), @@ -572,10 +572,10 @@ impl CircuitData { let qubits = PySet::empty_bound(py)?; let clbits = PySet::empty_bound(py)?; for inst in self.data.iter() { - for b in self.qargs_interner.intern(inst.qubits) { + for b in self.qargs_interner.get(inst.qubits) { qubits.add(self.qubits.get(*b).unwrap().clone_ref(py))?; } - for b in self.cargs_interner.intern(inst.clbits) { + for b in self.cargs_interner.get(inst.clbits) { clbits.add(self.clbits.get(*b).unwrap().clone_ref(py))?; } } @@ -737,8 +737,8 @@ impl CircuitData { // Get a single item, assuming the index is validated as in bounds. let get_single = |index: usize| { let inst = &self.data[index]; - let qubits = self.qargs_interner.intern(inst.qubits); - let clbits = self.cargs_interner.intern(inst.clbits); + let qubits = self.qargs_interner.get(inst.qubits); + let clbits = self.cargs_interner.get(inst.clbits); CircuitInstruction { operation: inst.op.clone(), qubits: PyTuple::new_bound(py, self.qubits.map_indices(qubits)).unbind(), @@ -894,7 +894,7 @@ impl CircuitData { for inst in other.data.iter() { let qubits = other .qargs_interner - .intern(inst.qubits) + .get(inst.qubits) .iter() .map(|b| { Ok(self @@ -905,7 +905,7 @@ impl CircuitData { .collect::>>()?; let clbits = other .cargs_interner - .intern(inst.clbits) + .get(inst.clbits) .iter() .map(|b| { Ok(self @@ -915,8 +915,8 @@ impl CircuitData { }) .collect::>>()?; let new_index = self.data.len(); - let qubits_id = Interner::intern(&mut self.qargs_interner, qubits)?; - let clbits_id = Interner::intern(&mut self.cargs_interner, clbits)?; + let qubits_id = self.qargs_interner.insert_owned(qubits); + let clbits_id = self.cargs_interner.insert_owned(clbits); self.data.push(PackedInstruction { op: inst.op.clone(), qubits: qubits_id, @@ -1113,14 +1113,12 @@ impl CircuitData { } fn pack(&mut self, py: Python, inst: &CircuitInstruction) -> PyResult { - let qubits = Interner::intern( - &mut self.qargs_interner, - self.qubits.map_bits(inst.qubits.bind(py))?.collect(), - )?; - let clbits = Interner::intern( - &mut self.cargs_interner, - self.clbits.map_bits(inst.clbits.bind(py))?.collect(), - )?; + let qubits = self + .qargs_interner + .insert_owned(self.qubits.map_bits(inst.qubits.bind(py))?.collect()); + let clbits = self + .cargs_interner + .insert_owned(self.clbits.map_bits(inst.clbits.bind(py))?.collect()); Ok(PackedInstruction { op: inst.operation.clone(), qubits, @@ -1138,12 +1136,12 @@ impl CircuitData { } /// Returns an immutable view of the Interner used for Qargs - pub fn qargs_interner(&self) -> &IndexedInterner> { + pub fn qargs_interner(&self) -> &Interner<[Qubit]> { &self.qargs_interner } /// Returns an immutable view of the Interner used for Cargs - pub fn cargs_interner(&self) -> &IndexedInterner> { + pub fn cargs_interner(&self) -> &Interner<[Clbit]> { &self.cargs_interner } @@ -1162,14 +1160,14 @@ impl CircuitData { &self.clbits } - /// Unpacks from InternerIndex to `[Qubit]` - pub fn get_qargs(&self, index: Index) -> &[Qubit] { - self.qargs_interner().intern(index) + /// Unpacks from interned value to `[Qubit]` + pub fn get_qargs(&self, index: Interned<[Qubit]>) -> &[Qubit] { + self.qargs_interner().get(index) } /// Unpacks from InternerIndex to `[Clbit]` - pub fn get_cargs(&self, index: Index) -> &[Clbit] { - self.cargs_interner().intern(index) + pub fn get_cargs(&self, index: Interned<[Clbit]>) -> &[Clbit] { + self.cargs_interner().get(index) } fn assign_parameters_inner(&mut self, py: Python, iter: I) -> PyResult<()> diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index bb5fff5e343a..4e1cf88092f8 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -22,7 +22,7 @@ use crate::dag_node::{DAGInNode, DAGNode, DAGOpNode, DAGOutNode}; use crate::dot_utils::build_dot; use crate::error::DAGCircuitError; use crate::imports; -use crate::interner::{IndexedInterner, Interner}; +use crate::interner::Interner; use crate::operations::{Operation, OperationRef, Param, PyInstruction}; use crate::packed_instruction::PackedInstruction; use crate::rustworkx_core_vnext::isomorphism; @@ -231,9 +231,9 @@ pub struct DAGCircuit { cregs: Py, /// The cache used to intern instruction qargs. - qargs_cache: IndexedInterner>, + qargs_interner: Interner<[Qubit]>, /// The cache used to intern instruction cargs. - cargs_cache: IndexedInterner>, + cargs_interner: Interner<[Clbit]>, /// Qubits registered in the circuit. pub qubits: BitData, /// Clbits registered in the circuit. @@ -415,8 +415,8 @@ impl DAGCircuit { dag: StableDiGraph::default(), qregs: PyDict::new_bound(py).unbind(), cregs: PyDict::new_bound(py).unbind(), - qargs_cache: IndexedInterner::new(), - cargs_cache: IndexedInterner::new(), + qargs_interner: Interner::new(), + cargs_interner: Interner::new(), qubits: BitData::new(py, "qubits".to_string()), clbits: BitData::new(py, "clbits".to_string()), global_phase: Param::Float(0.), @@ -1210,13 +1210,11 @@ def _format(operand): for node_weight in self.dag.node_weights_mut() { match node_weight { NodeType::Operation(op) => { - let cargs = self.cargs_cache.intern(op.clbits); - let carg_bits = old_clbits - .map_indices(&cargs[..]) - .map(|b| b.bind(py).clone()); - let mapped_cargs = self.clbits.map_bits(carg_bits)?.collect(); - let clbits = Interner::intern(&mut self.cargs_cache, mapped_cargs)?; - op.clbits = clbits; + let cargs = self.cargs_interner.get(op.clbits); + let carg_bits = old_clbits.map_indices(cargs).map(|b| b.bind(py).clone()); + op.clbits = self + .cargs_interner + .insert_owned(self.clbits.map_bits(carg_bits)?.collect()); } NodeType::ClbitIn(c) | NodeType::ClbitOut(c) => { *c = self @@ -1420,13 +1418,11 @@ def _format(operand): for node_weight in self.dag.node_weights_mut() { match node_weight { NodeType::Operation(op) => { - let qargs = self.qargs_cache.intern(op.qubits); - let qarg_bits = old_qubits - .map_indices(&qargs[..]) - .map(|b| b.bind(py).clone()); - let mapped_qargs = self.qubits.map_bits(qarg_bits)?.collect(); - let qubits = Interner::intern(&mut self.qargs_cache, mapped_qargs)?; - op.qubits = qubits; + let qargs = self.qargs_interner.get(op.qubits); + let qarg_bits = old_qubits.map_indices(qargs).map(|b| b.bind(py).clone()); + op.qubits = self + .qargs_interner + .insert_owned(self.qubits.map_bits(qarg_bits)?.collect()); } NodeType::QubitIn(q) | NodeType::QubitOut(q) => { *q = self @@ -1566,8 +1562,8 @@ def _format(operand): target_dag.duration = self.duration.as_ref().map(|d| d.clone_ref(py)); target_dag.unit.clone_from(&self.unit); target_dag.metadata = self.metadata.as_ref().map(|m| m.clone_ref(py)); - target_dag.qargs_cache = self.qargs_cache.clone(); - target_dag.cargs_cache = self.cargs_cache.clone(); + target_dag.qargs_interner = self.qargs_interner.clone(); + target_dag.cargs_interner = self.cargs_interner.clone(); for bit in self.qubits.bits() { target_dag.add_qubit_unchecked(py, bit.bind(py))?; @@ -1677,14 +1673,12 @@ def _format(operand): let qargs = qargs.map(|q| q.value); let cargs = cargs.map(|c| c.value); let node = { - let qubits_id = Interner::intern( - &mut self.qargs_cache, - self.qubits.map_bits(qargs.iter().flatten())?.collect(), - )?; - let clbits_id = Interner::intern( - &mut self.cargs_cache, - self.clbits.map_bits(cargs.iter().flatten())?.collect(), - )?; + let qubits_id = self + .qargs_interner + .insert_owned(self.qubits.map_bits(qargs.iter().flatten())?.collect()); + let clbits_id = self + .cargs_interner + .insert_owned(self.clbits.map_bits(cargs.iter().flatten())?.collect()); let instr = PackedInstruction { op: py_op.operation, qubits: qubits_id, @@ -1733,14 +1727,12 @@ def _format(operand): let qargs = qargs.map(|q| q.value); let cargs = cargs.map(|c| c.value); let node = { - let qubits_id = Interner::intern( - &mut self.qargs_cache, - self.qubits.map_bits(qargs.iter().flatten())?.collect(), - )?; - let clbits_id = Interner::intern( - &mut self.cargs_cache, - self.clbits.map_bits(cargs.iter().flatten())?.collect(), - )?; + let qubits_id = self + .qargs_interner + .insert_owned(self.qubits.map_bits(qargs.iter().flatten())?.collect()); + let clbits_id = self + .cargs_interner + .insert_owned(self.clbits.map_bits(cargs.iter().flatten())?.collect()); let instr = PackedInstruction { op: py_op.operation, qubits: qubits_id, @@ -1993,7 +1985,7 @@ def _format(operand): let m_qargs = { let qubits = other .qubits - .map_indices(other.qargs_cache.intern(op.qubits).as_slice()); + .map_indices(other.qargs_interner.get(op.qubits)); let mut mapped = Vec::with_capacity(qubits.len()); for bit in qubits { mapped.push( @@ -2007,7 +1999,7 @@ def _format(operand): let m_cargs = { let clbits = other .clbits - .map_indices(other.cargs_cache.intern(op.clbits).as_slice()); + .map_indices(other.cargs_interner.get(op.clbits)); let mut mapped = Vec::with_capacity(clbits.len()); for bit in clbits { mapped.push( @@ -2471,10 +2463,10 @@ def _format(operand): return Ok(false); } let check_args = || -> bool { - let node1_qargs = self.qargs_cache.intern(inst1.qubits); - let node2_qargs = other.qargs_cache.intern(inst2.qubits); - let node1_cargs = self.cargs_cache.intern(inst1.clbits); - let node2_cargs = other.cargs_cache.intern(inst2.clbits); + let node1_qargs = self.qargs_interner.get(inst1.qubits); + let node2_qargs = other.qargs_interner.get(inst2.qubits); + let node1_cargs = self.cargs_interner.get(inst1.clbits); + let node2_cargs = other.cargs_interner.get(inst2.clbits); if SEMANTIC_EQ_SYMMETRIC.contains(&inst1.op.name()) { let node1_qargs = node1_qargs.iter().copied().collect::>(); @@ -2752,8 +2744,8 @@ def _format(operand): match weight { Some(NodeType::Operation(packed)) => { block_op_names.push(packed.op.name().to_string()); - block_qargs.extend(self.qargs_cache.intern(packed.qubits)); - block_cargs.extend(self.cargs_cache.intern(packed.clbits)); + block_qargs.extend(self.qargs_interner.get(packed.qubits)); + block_cargs.extend(self.cargs_interner.get(packed.clbits)); if let Some(condition) = packed.condition() { block_cargs.extend( @@ -2828,8 +2820,8 @@ def _format(operand): } let op_name = py_op.operation.name().to_string(); - let qubits = Interner::intern(&mut self.qargs_cache, block_qargs)?; - let clbits = Interner::intern(&mut self.cargs_cache, block_cargs)?; + let qubits = self.qargs_interner.insert_owned(block_qargs); + let clbits = self.cargs_interner.insert_owned(block_cargs); let weight = NodeType::Operation(PackedInstruction { op: py_op.operation, qubits, @@ -3182,7 +3174,7 @@ def _format(operand): "cannot propagate a condition to an element that already has one", )); } - let cargs = input_dag.cargs_cache.intern(inst.clbits); + let cargs = input_dag.cargs_interner.get(inst.clbits); let cargs_bits: Vec = input_dag .clbits .map_indices(cargs) @@ -3437,13 +3429,13 @@ def _format(operand): .map(|e| e.weight().clone()) .collect(); let mut new_wires: HashSet = self - .qargs_cache - .intern(old_packed.qubits) + .qargs_interner + .get(old_packed.qubits) .iter() .map(|x| Wire::Qubit(*x)) .chain( - self.cargs_cache - .intern(old_packed.clbits) + self.cargs_interner + .get(old_packed.clbits) .iter() .map(|x| Wire::Clbit(*x)), ) @@ -3966,7 +3958,7 @@ def _format(operand): continue; } - let qargs = self.qargs_cache.intern(packed.qubits); + let qargs = self.qargs_interner.get(packed.qubits); if qargs.len() == 2 { nodes.push(self.unpack_into(py, node, weight)?); } @@ -3984,7 +3976,7 @@ def _format(operand): continue; } - let qargs = self.qargs_cache.intern(packed.qubits); + let qargs = self.qargs_interner.get(packed.qubits); if qargs.len() >= 3 { nodes.push(self.unpack_into(py, node, weight)?); } @@ -4348,7 +4340,7 @@ def _format(operand): py, new_layer .qubits - .map_indices(new_layer.qargs_cache.intern(node.qubits)), + .map_indices(new_layer.qargs_interner.get(node.qubits)), ) }); let support_list = PyList::empty_bound(py); @@ -4380,8 +4372,8 @@ def _format(operand): let support_list = PyList::empty_bound(py); let qubits = PyTuple::new_bound( py, - self.qargs_cache - .intern(retrieved_node.qubits) + self.qargs_interner + .get(retrieved_node.qubits) .iter() .map(|qubit| self.qubits.get(*qubit)), ) @@ -4685,7 +4677,7 @@ def _format(operand): if processed_non_directive_nodes.contains(&cur_index) { continue; } - qubits_in_cone.extend(self.qargs_cache.intern(packed.qubits).iter()); + qubits_in_cone.extend(self.qargs_interner.get(packed.qubits)); processed_non_directive_nodes.insert(cur_index); for pred_index in self.quantum_predecessors(cur_index) { @@ -4704,8 +4696,8 @@ def _format(operand): self.dag.node_weight(pred_index).unwrap() { if self - .qargs_cache - .intern(pred_packed.qubits) + .qargs_interner + .get(pred_packed.qubits) .iter() .any(|x| qubits_in_cone.contains(x)) { @@ -5165,7 +5157,7 @@ impl DAGCircuit { let (all_cbits, vars): (Vec, Option>) = { if self.may_have_additional_wires(py, &instr) { let mut clbits: HashSet = - HashSet::from_iter(self.cargs_cache.intern(instr.clbits).iter().copied()); + HashSet::from_iter(self.cargs_interner.get(instr.clbits).iter().copied()); let (additional_clbits, additional_vars) = self.additional_wires(py, instr.op.view(), instr.condition())?; for clbit in additional_clbits { @@ -5173,7 +5165,7 @@ impl DAGCircuit { } (clbits.into_iter().collect(), Some(additional_vars)) } else { - (self.cargs_cache.intern(instr.clbits).to_vec(), None) + (self.cargs_interner.get(instr.clbits).to_vec(), None) } }; @@ -5185,8 +5177,8 @@ impl DAGCircuit { // Put the new node in-between the previously "last" nodes on each wire // and the output map. let output_nodes: HashSet = self - .qargs_cache - .intern(qubits_id) + .qargs_interner + .get(qubits_id) .iter() .map(|q| self.qubit_io_map.get(q.0 as usize).map(|x| x[1]).unwrap()) .chain( @@ -5231,7 +5223,7 @@ impl DAGCircuit { let (all_cbits, vars): (Vec, Option>) = { if self.may_have_additional_wires(py, &inst) { let mut clbits: HashSet = - HashSet::from_iter(self.cargs_cache.intern(inst.clbits).iter().cloned()); + HashSet::from_iter(self.cargs_interner.get(inst.clbits).iter().copied()); let (additional_clbits, additional_vars) = self.additional_wires(py, inst.op.view(), inst.condition())?; for clbit in additional_clbits { @@ -5239,7 +5231,7 @@ impl DAGCircuit { } (clbits.into_iter().collect(), Some(additional_vars)) } else { - (self.cargs_cache.intern(inst.clbits).to_vec(), None) + (self.cargs_interner.get(inst.clbits).to_vec(), None) } }; @@ -5251,8 +5243,8 @@ impl DAGCircuit { // Put the new node in-between the input map and the previously // "first" nodes on each wire. let mut input_nodes: Vec = self - .qargs_cache - .intern(qubits_id) + .qargs_interner + .get(qubits_id) .iter() .map(|q| self.qubit_io_map[q.0 as usize][0]) .chain(all_cbits.iter().map(|c| self.clbit_io_map[c.0 as usize][0])) @@ -5282,8 +5274,8 @@ impl DAGCircuit { fn sort_key(&self, node: NodeIndex) -> SortKeyType { match &self.dag[node] { NodeType::Operation(packed) => ( - self.qargs_cache.intern(packed.qubits).as_slice(), - self.cargs_cache.intern(packed.clbits).as_slice(), + self.qargs_interner.get(packed.qubits), + self.cargs_interner.get(packed.clbits), ), NodeType::QubitIn(q) => (std::slice::from_ref(q), &[Clbit(u32::MAX)]), NodeType::QubitOut(_q) => (&[Qubit(u32::MAX)], &[Clbit(u32::MAX)]), @@ -5687,18 +5679,16 @@ impl DAGCircuit { } } else if let Ok(op_node) = b.downcast::() { let op_node = op_node.borrow(); - let qubits = Interner::intern( - &mut self.qargs_cache, + let qubits = self.qargs_interner.insert_owned( self.qubits .map_bits(op_node.instruction.qubits.bind(py))? .collect(), - )?; - let clbits = Interner::intern( - &mut self.cargs_cache, + ); + let clbits = self.cargs_interner.insert_owned( self.clbits .map_bits(op_node.instruction.clbits.bind(py))? .collect(), - )?; + ); let params = (!op_node.instruction.params.is_empty()) .then(|| Box::new(op_node.instruction.params.clone())); let inst = PackedInstruction { @@ -5739,8 +5729,8 @@ impl DAGCircuit { )? .into_any(), NodeType::Operation(packed) => { - let qubits = self.qargs_cache.intern(packed.qubits); - let clbits = self.cargs_cache.intern(packed.clbits); + let qubits = self.qargs_interner.get(packed.qubits); + let clbits = self.cargs_interner.get(packed.clbits); Py::new( py, ( @@ -5954,19 +5944,19 @@ impl DAGCircuit { let mut new_node = other.dag[old_index].clone(); if let NodeType::Operation(ref mut new_inst) = new_node { let new_qubit_indices: Vec = other - .qargs_cache - .intern(new_inst.qubits) + .qargs_interner + .get(new_inst.qubits) .iter() .map(|old_qubit| qubit_map[old_qubit]) .collect(); let new_clbit_indices: Vec = other - .cargs_cache - .intern(new_inst.clbits) + .cargs_interner + .get(new_inst.clbits) .iter() .map(|old_clbit| clbit_map[old_clbit]) .collect(); - new_inst.qubits = Interner::intern(&mut self.qargs_cache, new_qubit_indices)?; - new_inst.clbits = Interner::intern(&mut self.cargs_cache, new_clbit_indices)?; + new_inst.qubits = self.qargs_interner.insert_owned(new_qubit_indices); + new_inst.clbits = self.cargs_interner.insert_owned(new_clbit_indices); self.increment_op(new_inst.op.name()); } let new_index = self.dag.add_node(new_node); @@ -6128,7 +6118,7 @@ impl DAGCircuit { self._check_condition(py, inst.op.name(), condition.bind(py))?; } - for b in self.qargs_cache.intern(inst.qubits) { + for b in self.qargs_interner.get(inst.qubits) { if self.qubit_io_map.len() - 1 < b.0 as usize { return Err(DAGCircuitError::new_err(format!( "qubit {} not found in output map", @@ -6137,7 +6127,7 @@ impl DAGCircuit { } } - for b in self.cargs_cache.intern(inst.clbits) { + for b in self.cargs_interner.get(inst.clbits) { if !self.clbit_io_map.len() - 1 < b.0 as usize { return Err(DAGCircuitError::new_err(format!( "clbit {} not found in output map", diff --git a/crates/circuit/src/interner.rs b/crates/circuit/src/interner.rs index e19f56e87a7d..007256422e25 100644 --- a/crates/circuit/src/interner.rs +++ b/crates/circuit/src/interner.rs @@ -10,79 +10,154 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. +use std::borrow::Borrow; +use std::fmt; use std::hash::Hash; -use std::sync::Arc; +use std::marker::PhantomData; -use hashbrown::HashMap; -use pyo3::exceptions::PyRuntimeError; -use pyo3::prelude::*; +use indexmap::IndexSet; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Index(u32); - -impl IntoPy for Index { - fn into_py(self, py: Python<'_>) -> PyObject { - self.0.into_py(py) - } +/// A key to retrieve a value (by reference) from an interner of the same type. This is narrower +/// than a true reference, at the cost that it is explicitly not lifetime bound to the interner it +/// came from; it is up to the user to ensure that they never attempt to query an interner with a +/// key from a different interner. +#[derive(Debug, Eq, PartialEq)] +pub struct Interned { + index: u32, + // Storing the type of the interned value adds a small amount more type safety to the interner + // keys when there's several interners in play close to each other. We use `*const T` because + // the `Interned value` is like a non-lifetime-bound reference to data stored in the interner; + // `Interned` doesn't own the data (which would be implied by `T`), and it's not using the + // static lifetime system (which would be implied by `&'_ T`, and require us to propagate the + // lifetime bound). + _type: PhantomData<*const T>, } - -/// An append-only data structure for interning generic -/// Rust types. -#[derive(Clone, Debug)] -pub struct IndexedInterner { - entries: Vec>, - index_lookup: HashMap, Index>, +// The `PhantomData` marker prevents various useful things from being derived (for `Clone` and +// `Copy` it's an awkward effect of the derivation system), so we have manual implementations. +impl Clone for Interned { + fn clone(&self) -> Self { + *self + } } +impl Copy for Interned {} +unsafe impl Send for Interned {} +unsafe impl Sync for Interned {} -pub trait Interner { - type Output; +/// An append-only data structure for interning generic Rust types. +/// +/// The interner can lookup keys using a reference type, and will create the corresponding owned +/// allocation on demand, if a matching entry is not already stored. It returns manual keys into +/// itself (the `Interned` type), rather than raw references; the `Interned` type is narrower than a +/// true reference. +/// +/// # Examples +/// +/// ```rust +/// let mut interner = Interner::<[usize]>::new(); +/// +/// // These are of type `Interned<[usize]>`. +/// let empty = interner.insert(&[]); +/// let other_empty = interner.insert(&[]); +/// let key = interner.insert(&[0, 1, 2, 3, 4]); +/// +/// assert_eq!(empty, other_empty); +/// assert_ne!(empty, key); +/// +/// assert_eq!(interner.get(empty), &[]); +/// assert_eq!(interner.get(key), &[0, 1, 2, 3, 4]); +/// ``` +#[derive(Default)] +pub struct Interner(IndexSet<::Owned, ::ahash::RandomState>); - /// Takes ownership of the provided key and returns the interned - /// type. - fn intern(self, value: K) -> Self::Output; +// `Clone` and `Debug` can't use the derivation mechanism because the values that are actually +// stored are of type `::Owned`, which the derive system doesn't reason about. +impl Clone for Interner +where + T: ?Sized + ToOwned, + ::Owned: Clone, +{ + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl fmt::Debug for Interner +where + T: ?Sized + ToOwned, + ::Owned: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_tuple("Interner").field(&self.0).finish() + } } -impl<'a, T> Interner for &'a IndexedInterner { - type Output = &'a T; - - fn intern(self, index: Index) -> Self::Output { - let value = self.entries.get(index.0 as usize).unwrap(); - value.as_ref() +impl Interner +where + T: ?Sized + ToOwned, +{ + pub fn new() -> Self { + Self(Default::default()) } } -impl<'a, T> Interner for &'a mut IndexedInterner +impl Interner where - T: Eq + Hash, + T: ?Sized + ToOwned, + ::Owned: Hash + Eq, { - type Output = PyResult; + /// Retrieve a reference to the stored value for this key. + pub fn get(&self, index: Interned) -> &T { + self.0 + .get_index(index.index as usize) + .expect( + "the caller is responsible for only using interner keys from the correct interner", + ) + .borrow() + } - fn intern(self, key: T) -> Self::Output { - if let Some(index) = self.index_lookup.get(&key).copied() { - Ok(index) - } else { - let args = Arc::new(key); - let index: Index = Index(self.entries.len().try_into().map_err(|_| { - PyRuntimeError::new_err("The interner has run out of indices (cache is full)!") - })?); - self.entries.push(args.clone()); - self.index_lookup.insert_unique_unchecked(args, index); - Ok(index) + /// Internal worker function that inserts an owned value assuming that the value didn't + /// previously exist in the map. + fn insert_new(&mut self, value: ::Owned) -> u32 { + let index = self.0.len(); + if index == u32::MAX as usize { + panic!("interner is out of space"); } + let _inserted = self.0.insert(value); + debug_assert!(_inserted); + index as u32 } -} -impl IndexedInterner { - pub fn new() -> Self { - IndexedInterner { - entries: Vec::new(), - index_lookup: HashMap::new(), + /// Get an interner key corresponding to the given referenced type. If not already stored, this + /// function will allocate a new owned value to use as the storage. + /// + /// If you already have an owned value, use `insert_owned`, but in general this function will be + /// more efficient *unless* you already had the value for other reasons. + pub fn insert(&mut self, value: &T) -> Interned + where + T: Hash + Eq, + { + let index = match self.0.get_index_of(value) { + Some(index) => index as u32, + None => self.insert_new(value.to_owned()), + }; + Interned { + index, + _type: PhantomData, } } -} -impl Default for IndexedInterner { - fn default() -> Self { - Self::new() + /// Get an interner key corresponding to the given owned type. If not already stored, the value + /// will be used as the key, otherwise it will be dropped. + /// + /// If you don't already have the owned value, use `insert`; this will only allocate if the + /// lookup fails. + pub fn insert_owned(&mut self, value: ::Owned) -> Interned { + let index = match self.0.get_index_of(&value) { + Some(index) => index as u32, + None => self.insert_new(value), + }; + Interned { + index, + _type: PhantomData, + } } } diff --git a/crates/circuit/src/packed_instruction.rs b/crates/circuit/src/packed_instruction.rs index 7619ecb9c525..77ca0c6c02dd 100644 --- a/crates/circuit/src/packed_instruction.rs +++ b/crates/circuit/src/packed_instruction.rs @@ -25,9 +25,11 @@ use smallvec::SmallVec; use crate::circuit_data::CircuitData; use crate::circuit_instruction::ExtraInstructionAttributes; use crate::imports::{get_std_gate_class, DEEPCOPY}; +use crate::interner::Interned; use crate::operations::{ Operation, OperationRef, Param, PyGate, PyInstruction, PyOperation, StandardGate, }; +use crate::{Clbit, Qubit}; /// The logical discriminant of `PackedOperation`. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -491,9 +493,9 @@ impl Drop for PackedOperation { pub struct PackedInstruction { pub op: PackedOperation, /// The index under which the interner has stored `qubits`. - pub qubits: crate::interner::Index, + pub qubits: Interned<[Qubit]>, /// The index under which the interner has stored `clbits`. - pub clbits: crate::interner::Index, + pub clbits: Interned<[Clbit]>, pub params: Option>>, pub extra_attrs: Option>, From 37784c763c205fd8ca885c53d86e9beac7a6d3fe Mon Sep 17 00:00:00 2001 From: Kevin Hartman Date: Wed, 28 Aug 2024 08:51:04 -0400 Subject: [PATCH 27/85] Fully port `Depth` and `Size` passes to Rust (#13040) * Avoid isinstance check on every node in DAG during recursive depth and size calls. * Avoid unnecessary downcast. * Check if there is control flow before doing loops. * Avoid py_op_nodes in DAGCircuit::count_ops. --- crates/circuit/src/dag_circuit.rs | 193 +++++++++++++++--------------- 1 file changed, 95 insertions(+), 98 deletions(-) diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 4e1cf88092f8..b6e33e78c1b2 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -2145,53 +2145,46 @@ def _format(operand): #[pyo3(signature= (*, recurse=false))] fn size(&self, py: Python, recurse: bool) -> PyResult { let mut length = self.dag.node_count() - (self.width() * 2); - if !recurse { - if CONTROL_FLOW_OP_NAMES - .iter() - .any(|n| self.op_names.contains_key(&n.to_string())) - { - return Err(DAGCircuitError::new_err(concat!( - "Size with control flow is ambiguous.", - " You may use `recurse=True` to get a result", - " but see this method's documentation for the meaning of this." - ))); - } + if !self.has_control_flow() { return Ok(length); } + if !recurse { + return Err(DAGCircuitError::new_err(concat!( + "Size with control flow is ambiguous.", + " You may use `recurse=True` to get a result", + " but see this method's documentation for the meaning of this." + ))); + } + // Handle recursively. let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); - for node_index in - self.op_nodes_by_py_type(imports::CONTROL_FLOW_OP.get_bound(py).downcast()?, true) - { - let NodeType::Operation(node) = &self.dag[node_index] else { - return Err(DAGCircuitError::new_err("unknown control-flow type")); + for node in self.dag.node_weights() { + let NodeType::Operation(node) = node else { + continue; }; + if !node.op.control_flow() { + continue; + } let OperationRef::Instruction(inst) = node.op.view() else { - unreachable!("Control Flow operations must be a PyInstruction"); + panic!("control flow op must be an instruction"); }; let inst_bound = inst.instruction.bind(py); if inst_bound.is_instance(imports::FOR_LOOP_OP.get_bound(py))? { - let raw_blocks = inst_bound.getattr("blocks")?; - let blocks: &Bound = raw_blocks.downcast()?; - let block_zero = blocks.get_item(0).unwrap(); - let inner_dag: &DAGCircuit = - &circuit_to_dag.call1((block_zero.clone(),))?.extract()?; + let blocks = inst_bound.getattr("blocks")?; + let block_zero = blocks.get_item(0)?; + let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block_zero,))?.extract()?; length += node.params_view().len() * inner_dag.size(py, true)? } else if inst_bound.is_instance(imports::WHILE_LOOP_OP.get_bound(py))? { - let raw_blocks = inst_bound.getattr("blocks")?; - let blocks: &Bound = raw_blocks.downcast()?; - let block_zero = blocks.get_item(0).unwrap(); - let inner_dag: &DAGCircuit = - &circuit_to_dag.call1((block_zero.clone(),))?.extract()?; + let blocks = inst_bound.getattr("blocks")?; + let block_zero = blocks.get_item(0)?; + let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block_zero,))?.extract()?; length += inner_dag.size(py, true)? } else if inst_bound.is_instance(imports::IF_ELSE_OP.get_bound(py))? || inst_bound.is_instance(imports::SWITCH_CASE_OP.get_bound(py))? { - let raw_blocks = inst_bound.getattr("blocks")?; - let blocks: &Bound = raw_blocks.downcast()?; - for block in blocks.iter() { - let inner_dag: &DAGCircuit = - &circuit_to_dag.call1((block.clone(),))?.extract()?; + let blocks = inst_bound.getattr("blocks")?; + for block in blocks.iter()? { + let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block?,))?.extract()?; length += inner_dag.size(py, true)?; } } else { @@ -2227,62 +2220,60 @@ def _format(operand): if self.qubits.is_empty() && self.clbits.is_empty() && self.vars_info.is_empty() { return Ok(0); } + if !self.has_control_flow() { + let weight_fn = |_| -> Result { Ok(1) }; + return match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { + Some(res) => Ok(res.1 - 1), + None => Err(DAGCircuitError::new_err("not a DAG")), + }; + } + if !recurse { + return Err(DAGCircuitError::new_err(concat!( + "Depth with control flow is ambiguous.", + " You may use `recurse=True` to get a result", + " but see this method's documentation for the meaning of this." + ))); + } - Ok(if recurse { - let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); - let mut node_lookup: HashMap = HashMap::new(); - - for node_index in - self.op_nodes_by_py_type(imports::CONTROL_FLOW_OP.get_bound(py).downcast()?, true) - { - if let NodeType::Operation(node) = &self.dag[node_index] { - if let OperationRef::Instruction(inst) = node.op.view() { - let inst_bound = inst.instruction.bind(py); - let weight = - if inst_bound.is_instance(imports::FOR_LOOP_OP.get_bound(py))? { - node.params_view().len() - } else { - 1 - }; - if weight == 0 { - node_lookup.insert(node_index, 0); - } else { - let raw_blocks = inst_bound.getattr("blocks")?; - let blocks = raw_blocks.downcast::()?; - let mut block_weights: Vec = Vec::with_capacity(blocks.len()); - for block in blocks.iter() { - let inner_dag: &DAGCircuit = - &circuit_to_dag.call1((block,))?.extract()?; - block_weights.push(inner_dag.depth(py, true)?); - } - node_lookup - .insert(node_index, weight * block_weights.iter().max().unwrap()); - } - } - } - } - - let weight_fn = |edge: EdgeReference<'_, Wire>| -> Result { - Ok(*node_lookup.get(&edge.target()).unwrap_or(&1)) + // Handle recursively. + let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); + let mut node_lookup: HashMap = HashMap::new(); + for (node_index, node) in self.dag.node_references() { + let NodeType::Operation(node) = node else { + continue; }; - match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { - Some(res) => res.1, - None => return Err(DAGCircuitError::new_err("not a DAG")), + if !node.op.control_flow() { + continue; } - } else { - if CONTROL_FLOW_OP_NAMES - .iter() - .any(|x| self.op_names.contains_key(&x.to_string())) - { - return Err(DAGCircuitError::new_err("Depth with control flow is ambiguous. You may use `recurse=True` to get a result, but see this method's documentation for the meaning of this.")); + let OperationRef::Instruction(inst) = node.op.view() else { + panic!("control flow op must be an instruction") + }; + let inst_bound = inst.instruction.bind(py); + let weight = if inst_bound.is_instance(imports::FOR_LOOP_OP.get_bound(py))? { + node.params_view().len() + } else { + 1 + }; + if weight == 0 { + node_lookup.insert(node_index, 0); + } else { + let blocks = inst_bound.getattr("blocks")?; + let mut block_weights: Vec = Vec::with_capacity(blocks.len()?); + for block in blocks.iter()? { + let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block?,))?.extract()?; + block_weights.push(inner_dag.depth(py, true)?); + } + node_lookup.insert(node_index, weight * block_weights.iter().max().unwrap()); } + } - let weight_fn = |_| -> Result { Ok(1) }; - match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { - Some(res) => res.1, - None => return Err(DAGCircuitError::new_err("not a DAG")), - } - } - 1) + let weight_fn = |edge: EdgeReference<'_, Wire>| -> Result { + Ok(*node_lookup.get(&edge.target()).unwrap_or(&1)) + }; + match rustworkx_core::dag_algo::longest_path(&self.dag, weight_fn).unwrap() { + Some(res) => Ok(res.1 - 1), + None => Err(DAGCircuitError::new_err("not a DAG")), + } } /// Return the total number of qubits + clbits used by the circuit. @@ -4554,11 +4545,7 @@ def _format(operand): /// Mapping[str, int]: a mapping of operation names to the number of times it appears. #[pyo3(signature = (*, recurse=true))] fn count_ops(&self, py: Python, recurse: bool) -> PyResult { - if !recurse - || !CONTROL_FLOW_OP_NAMES - .iter() - .any(|x| self.op_names.contains_key(*x)) - { + if !recurse || !self.has_control_flow() { Ok(self.op_names.to_object(py)) } else { fn inner( @@ -4573,16 +4560,19 @@ def _format(operand): .or_insert(*value); } let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); - for node in dag.py_op_nodes( - py, - Some(imports::CONTROL_FLOW_OP.get_bound(py).downcast()?), - true, - )? { - let raw_blocks = node.getattr(py, "op")?.getattr(py, "blocks")?; - let blocks: &Bound = raw_blocks.downcast_bound::(py)?; - for block in blocks.iter() { - let inner_dag: &DAGCircuit = - &circuit_to_dag.call1((block.clone(),))?.extract()?; + for node in dag.dag.node_weights() { + let NodeType::Operation(node) = node else { + continue; + }; + if !node.op.control_flow() { + continue; + } + let OperationRef::Instruction(inst) = node.op.view() else { + panic!("control flow op must be an instruction") + }; + let blocks = inst.instruction.bind(py).getattr("blocks")?; + for block in blocks.iter()? { + let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block?,))?.extract()?; inner(py, inner_dag, counts)?; } } @@ -5332,6 +5322,13 @@ impl DAGCircuit { ) } + #[inline] + fn has_control_flow(&self) -> bool { + CONTROL_FLOW_OP_NAMES + .iter() + .any(|x| self.op_names.contains_key(&x.to_string())) + } + fn is_wire_idle(&self, py: Python, wire: &Wire) -> PyResult { let (input_node, output_node) = match wire { Wire::Qubit(qubit) => ( From cc2edc9f7172d75ec454fdaf5748326cd3720f90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 08:51:13 -0400 Subject: [PATCH 28/85] Bump bytemuck from 1.17.0 to 1.17.1 (#13049) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.17.0 to 1.17.1. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.17.0...v1.17.1) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 394e03f5d122..136ca4bed376 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" +checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" dependencies = [ "bytemuck_derive", ] From f37bd68005a88f82715e7b65326e941ff021406e Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Fri, 30 Aug 2024 00:44:18 +0100 Subject: [PATCH 29/85] Promote `CONTROL_FLOW_OP_NAMES` to public API (#13057) This is generally useful for Qiskit's built-in transpiler passes, and we've had some interest in using it for the same reasons from outside the library. While the control-flow structure from within Rust might change in the future, in the immediate term and from Python space, it feels fair to expose this as public API, since all the information contained in it is certainly already public. --- qiskit/circuit/__init__.py | 8 ++++++++ qiskit/circuit/controlflow/__init__.py | 1 + .../notes/control-flow-op-names-c66f38f8a0e15ce7.yaml | 5 +++++ 3 files changed, 14 insertions(+) create mode 100644 releasenotes/notes/control-flow-op-names-c66f38f8a0e15ce7.yaml diff --git a/qiskit/circuit/__init__.py b/qiskit/circuit/__init__.py index 1ab084ef2072..ebaef39c2a43 100644 --- a/qiskit/circuit/__init__.py +++ b/qiskit/circuit/__init__.py @@ -686,6 +686,13 @@ ControlFlowOp +For convenience, there is a :class:`frozenset` instance containing the :attr:`.Instruction.name` +attributes of each of the control-flow operations. + +.. data:: CONTROL_FLOW_OP_NAMES + + Set of the instruction names of Qiskit's known control-flow operations. + These control-flow operations (:class:`IfElseOp`, :class:`WhileLoopOp`, :class:`SwitchCaseOp` and :class:`ForLoopOp`) all have specific state that defines the branching conditions and strategies, but contain all the different subcircuit blocks that might be entered in @@ -1257,6 +1264,7 @@ def __array__(self, dtype=None, copy=None): CASE_DEFAULT, BreakLoopOp, ContinueLoopOp, + CONTROL_FLOW_OP_NAMES, ) from .annotated_operation import AnnotatedOperation, InverseModifier, ControlModifier, PowerModifier diff --git a/qiskit/circuit/controlflow/__init__.py b/qiskit/circuit/controlflow/__init__.py index 12831ccaaaed..2679b45d7782 100644 --- a/qiskit/circuit/controlflow/__init__.py +++ b/qiskit/circuit/controlflow/__init__.py @@ -25,3 +25,4 @@ CONTROL_FLOW_OP_NAMES = frozenset(("for_loop", "while_loop", "if_else", "switch_case")) +"""Set of the instruction names of Qiskit's known control-flow operations.""" diff --git a/releasenotes/notes/control-flow-op-names-c66f38f8a0e15ce7.yaml b/releasenotes/notes/control-flow-op-names-c66f38f8a0e15ce7.yaml new file mode 100644 index 000000000000..94a3b11b935b --- /dev/null +++ b/releasenotes/notes/control-flow-op-names-c66f38f8a0e15ce7.yaml @@ -0,0 +1,5 @@ +--- +features_circuits: + - | + A new data attribute, :data:`qiskit.circuit.CONTROL_FLOW_OP_NAMES`, is available to easily find + and check whether a given :class:`~.circuit.Instruction` is a control-flow operation by name. From edb249ec1a8c783feed61199f64fb7a5af16234c Mon Sep 17 00:00:00 2001 From: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:46:05 -0400 Subject: [PATCH 30/85] Add rust friendly `assign parameters` methods (#12913) * Initial: Add `assign_parameter` methods that can be used from Rust. * Add: Error message in `from_slice` method. - Accept owned mapping for `from_mapping`. * Fix: Use `assign_parameters_from_slice` as inner method for `assign_parameters_sequence` * Fix: Use `ParameterUuid` as keys for `assign_parameter_from_mapping` * Fix: Accept Param references in `assign_parameters_inner` * Fix: Ownership issues - Remove initial allocation of `Param` instances within a vec in `assign_parameters_iterable`. - Revert changes in `assign_parameters_mapping`. - Fix error message in `assign_parameter_from_slice`. - Return an error if a `uuid` is not found in `assign_parameters from mapping. Also, return error if a valid uuid is not found to avoid panicking. - Add `clone_ref(py)` method to `Param` to ensure that we use the most efficient cloning methods (either `clone_ref` with gil or copying). - Implement trait `AsRef` for `Param` to be able to send both owned and non-owned instances to `assign_parameters_inner`. * Docs: Add comment on `AsRef` impl block. --- crates/circuit/src/circuit_data.rs | 103 ++++++++++++++++++++--------- crates/circuit/src/operations.rs | 18 +++++ 2 files changed, 88 insertions(+), 33 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 640eb22b9401..72eaa34d4142 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -953,28 +953,16 @@ impl CircuitData { sequence.py(), array .iter() + .map(|value| Param::Float(*value)) .zip(old_table.drain_ordered()) - .map(|(value, (param_ob, uses))| (param_ob, Param::Float(*value), uses)), + .map(|(value, (obj, uses))| (obj, value, uses)), ) } else { let values = sequence .iter()? .map(|ob| Param::extract_no_coerce(&ob?)) .collect::>>()?; - if values.len() != self.param_table.num_parameters() { - return Err(PyValueError::new_err(concat!( - "Mismatching number of values and parameters. For partial binding ", - "please pass a dictionary of {parameter: value} pairs." - ))); - } - let mut old_table = std::mem::take(&mut self.param_table); - self.assign_parameters_inner( - sequence.py(), - values - .into_iter() - .zip(old_table.drain_ordered()) - .map(|(value, (param_ob, uses))| (param_ob, value, uses)), - ) + self.assign_parameters_from_slice(sequence.py(), &values) } } @@ -1135,6 +1123,50 @@ impl CircuitData { self.data.iter() } + /// Assigns parameters to circuit data based on a slice of `Param`. + pub fn assign_parameters_from_slice(&mut self, py: Python, slice: &[Param]) -> PyResult<()> { + if slice.len() != self.param_table.num_parameters() { + return Err(PyValueError::new_err(concat!( + "Mismatching number of values and parameters. For partial binding ", + "please pass a mapping of {parameter: value} pairs." + ))); + } + let mut old_table = std::mem::take(&mut self.param_table); + self.assign_parameters_inner( + py, + slice + .iter() + .zip(old_table.drain_ordered()) + .map(|(value, (param_ob, uses))| (param_ob, value.clone_ref(py), uses)), + ) + } + + /// Assigns parameters to circuit data based on a mapping of `ParameterUuid` : `Param`. + /// This mapping assumes that the provided `ParameterUuid` keys are instances + /// of `ParameterExpression`. + pub fn assign_parameters_from_mapping(&mut self, py: Python, iter: I) -> PyResult<()> + where + I: IntoIterator, + T: AsRef, + { + let mut items = Vec::new(); + for (param_uuid, value) in iter { + // Assume all the Parameters are already in the circuit + let param_obj = self.get_parameter_by_uuid(param_uuid); + if let Some(param_obj) = param_obj { + // Copy or increase ref_count for Parameter, avoid acquiring the GIL. + items.push(( + param_obj.clone_ref(py), + value.as_ref().clone_ref(py), + self.param_table.pop(param_uuid)?, + )); + } else { + return Err(PyValueError::new_err("An invalid parameter was provided.")); + } + } + self.assign_parameters_inner(py, items) + } + /// Returns an immutable view of the Interner used for Qargs pub fn qargs_interner(&self) -> &Interner<[Qubit]> { &self.qargs_interner @@ -1170,9 +1202,10 @@ impl CircuitData { self.cargs_interner().get(index) } - fn assign_parameters_inner(&mut self, py: Python, iter: I) -> PyResult<()> + fn assign_parameters_inner(&mut self, py: Python, iter: I) -> PyResult<()> where - I: IntoIterator, Param, HashSet)>, + I: IntoIterator, T, HashSet)>, + T: AsRef + Clone, { let inconsistent = || PyRuntimeError::new_err("internal error: circuit parameter table is inconsistent"); @@ -1209,7 +1242,7 @@ impl CircuitData { for (param_ob, value, uses) in iter { debug_assert!(!uses.is_empty()); uuids.clear(); - for inner_param_ob in value.iter_parameters(py)? { + for inner_param_ob in value.as_ref().iter_parameters(py)? { uuids.push(self.param_table.track(&inner_param_ob?, None)?) } for usage in uses { @@ -1220,7 +1253,7 @@ impl CircuitData { }; self.set_global_phase( py, - bind_expr(expr.bind_borrowed(py), ¶m_ob, &value, true)?, + bind_expr(expr.bind_borrowed(py), ¶m_ob, value.as_ref(), true)?, )?; } ParameterUse::Index { @@ -1234,17 +1267,21 @@ impl CircuitData { let Param::ParameterExpression(expr) = ¶ms[parameter] else { return Err(inconsistent()); }; - params[parameter] = - match bind_expr(expr.bind_borrowed(py), ¶m_ob, &value, true)? { - Param::Obj(obj) => { - return Err(CircuitError::new_err(format!( - "bad type after binding for gate '{}': '{}'", - standard.name(), - obj.bind(py).repr()?, - ))) - } - param => param, - }; + params[parameter] = match bind_expr( + expr.bind_borrowed(py), + ¶m_ob, + value.as_ref(), + true, + )? { + Param::Obj(obj) => { + return Err(CircuitError::new_err(format!( + "bad type after binding for gate '{}': '{}'", + standard.name(), + obj.bind(py).repr()?, + ))) + } + param => param, + }; for uuid in uuids.iter() { self.param_table.add_use(*uuid, usage)? } @@ -1264,7 +1301,7 @@ impl CircuitData { user_operations .entry(instruction) .or_insert_with(Vec::new) - .push((param_ob.clone_ref(py), value.clone())); + .push((param_ob.clone_ref(py), value.as_ref().clone_ref(py))); let op = previous.unpack_py_op(py)?.into_bound(py); let previous_param = &previous.params_view()[parameter]; @@ -1276,7 +1313,7 @@ impl CircuitData { let new_param = bind_expr( expr.bind_borrowed(py), ¶m_ob, - &value, + value.as_ref(), false, )?; // Historically, `assign_parameters` called `validate_parameter` @@ -1305,7 +1342,7 @@ impl CircuitData { Param::extract_no_coerce( &obj.call_method( assign_parameters_attr, - ([(¶m_ob, &value)].into_py_dict_bound(py),), + ([(¶m_ob, value.as_ref())].into_py_dict_bound(py),), Some( &[("inplace", false), ("flat_input", true)] .into_py_dict_bound(py), diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index ccf41d7eefb2..f6e087a5680f 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -125,6 +125,24 @@ impl Param { Param::Obj(ob.clone().unbind()) }) } + + /// Clones the [Param] object safely by reference count or copying. + pub fn clone_ref(&self, py: Python) -> Self { + match self { + Param::ParameterExpression(exp) => Param::ParameterExpression(exp.clone_ref(py)), + Param::Float(float) => Param::Float(*float), + Param::Obj(obj) => Param::Obj(obj.clone_ref(py)), + } + } +} + +// This impl allows for shared usage between [Param] and &[Param]. +// Such blanked impl doesn't exist inherently due to Rust's type system limitations. +// See https://doc.rust-lang.org/std/convert/trait.AsRef.html#reflexivity for more information. +impl AsRef for Param { + fn as_ref(&self) -> &Param { + self + } } /// Struct to provide iteration over Python-space `Parameter` instances within a `Param`. From 05a9b55db9e0a4909bd6e2cad0750a29beb3bb60 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Fri, 30 Aug 2024 15:25:27 +0100 Subject: [PATCH 31/85] Remove legacy-editable option from setuptools builds (#13059) We needed this back when `setuptools` first introduced the new editable installations, but at this point it should work more correctly without it; our non-CI configurations haven't included it for some time. --- .azure/test-linux.yml | 4 ---- .azure/test-macos.yml | 2 -- .azure/test-windows.yml | 2 -- .github/workflows/coverage.yml | 1 - .github/workflows/slow.yml | 2 -- 5 files changed, 11 deletions(-) diff --git a/.azure/test-linux.yml b/.azure/test-linux.yml index a773c15add50..a641ae215efd 100644 --- a/.azure/test-linux.yml +++ b/.azure/test-linux.yml @@ -92,8 +92,6 @@ jobs: # Build and install both qiskit and qiskit-terra so that any optionals # depending on `qiskit` will resolve correctly. displayName: "Install Terra directly" - env: - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - ${{ if eq(parameters.installOptionals, true) }}: - bash: | @@ -178,8 +176,6 @@ jobs: sudo apt-get install -y graphviz pandoc image_tests/bin/pip check displayName: 'Install dependencies' - env: - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - bash: | echo "##vso[task.setvariable variable=HAVE_VISUAL_TESTS_RUN;]true" diff --git a/.azure/test-macos.yml b/.azure/test-macos.yml index b167df3f1c82..9e9620e8ecbb 100644 --- a/.azure/test-macos.yml +++ b/.azure/test-macos.yml @@ -48,8 +48,6 @@ jobs: # depending on `qiskit` will resolve correctly. pip check displayName: 'Install dependencies' - env: - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - ${{ if eq(parameters.installOptionals, true) }}: - bash: | diff --git a/.azure/test-windows.yml b/.azure/test-windows.yml index eed1ef3eb6f8..8d86456bd72f 100644 --- a/.azure/test-windows.yml +++ b/.azure/test-windows.yml @@ -47,8 +47,6 @@ jobs: # depending on `qiskit` will resolve correctly. pip check displayName: 'Install dependencies' - env: - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - ${{ if eq(parameters.installOptionals, true) }}: - bash: | diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 33dc654801e1..95a0bda5d421 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -47,7 +47,6 @@ jobs: CARGO_INCREMENTAL: 0 RUSTFLAGS: "-Cinstrument-coverage" LLVM_PROFILE_FILE: "qiskit-%p-%m.profraw" - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - name: Generate unittest coverage report run: | diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 7f503b7de735..0207b1ec51f7 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -21,8 +21,6 @@ jobs: python -m pip install -U -r requirements-dev.txt -c constraints.txt python -m pip install -c constraints.txt -e . python -m pip install "qiskit-aer" "z3-solver" "cplex" -c constraints.txt - env: - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - name: Run all tests including slow run: stestr run env: From 31fbcacccabf464a56652edb082cb7e69df71622 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Fri, 30 Aug 2024 16:07:18 +0100 Subject: [PATCH 32/85] Add no-hash-lookup way to retrieve the default interned value (#13035) * Add no-hash-lookup way to retrieve the default interned value This makes it possible to do `Interner::get_default()` without any value, in order to retrieve a key pointing to the default allocation without making any hash lookups. While the hashing and equality check of the default allocation is typically very cheap (like the empty slice), acquiring it still generally required a function call, which often needed to be paid frequently. * Add symmetric method on `Interned` * Tweak documentation wording Co-authored-by: Kevin Hartman * Re-remove `Interned::of_default` following review --------- Co-authored-by: Kevin Hartman --- crates/circuit/src/circuit_data.rs | 4 ++-- crates/circuit/src/interner.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 72eaa34d4142..1aed43de0a21 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -199,7 +199,7 @@ impl CircuitData { instruction_iter.size_hint().0, global_phase, )?; - let no_clbit_index = res.cargs_interner.insert(&[]); + let no_clbit_index = res.cargs_interner.get_default(); for (operation, params, qargs) in instruction_iter { let qubits = res.qargs_interner.insert(&qargs); let params = (!params.is_empty()).then(|| Box::new(params)); @@ -258,7 +258,7 @@ impl CircuitData { params: &[Param], qargs: &[Qubit], ) -> PyResult<()> { - let no_clbit_index = self.cargs_interner.insert(&[]); + let no_clbit_index = self.cargs_interner.get_default(); let params = (!params.is_empty()).then(|| Box::new(params.iter().cloned().collect())); let qubits = self.qargs_interner.insert(qargs); self.data.push(PackedInstruction { diff --git a/crates/circuit/src/interner.rs b/crates/circuit/src/interner.rs index 007256422e25..39c5364aa1cc 100644 --- a/crates/circuit/src/interner.rs +++ b/crates/circuit/src/interner.rs @@ -50,17 +50,23 @@ unsafe impl Sync for Interned {} /// itself (the `Interned` type), rather than raw references; the `Interned` type is narrower than a /// true reference. /// +/// This is only implemented for owned types that implement `Default`, so that the convenience +/// method `Interner::get_default` can work reliably and correctly; the "default" index needs to be +/// guaranteed to be reserved and present for safety. +/// /// # Examples /// /// ```rust /// let mut interner = Interner::<[usize]>::new(); /// /// // These are of type `Interned<[usize]>`. +/// let default_empty = interner.get_default(); /// let empty = interner.insert(&[]); /// let other_empty = interner.insert(&[]); /// let key = interner.insert(&[0, 1, 2, 3, 4]); /// /// assert_eq!(empty, other_empty); +/// assert_eq!(empty, default_empty); /// assert_ne!(empty, key); /// /// assert_eq!(interner.get(empty), &[]); @@ -93,9 +99,31 @@ where impl Interner where T: ?Sized + ToOwned, + ::Owned: Hash + Eq + Default, { + /// Construct a new interner. The stored type must have a default value, in order for + /// `Interner::get_default` to reliably work correctly without a hash lookup (though ideally + /// we'd just use specialisation to do that). pub fn new() -> Self { - Self(Default::default()) + let mut set = IndexSet::with_capacity_and_hasher(1, Default::default()); + set.insert(Default::default()); + Self(set) + } + + /// Retrieve the key corresponding to the default store, without any hash or equality lookup. + /// For example, if the interned type is `[Clbit]`, the default key corresponds to the empty + /// slice `&[]`. This is a common operation with the cargs interner, for things like pushing + /// gates. + /// + /// In an ideal world, we wouldn't have the `Default` trait bound on `new`, but would use + /// specialisation to insert the default key only if the stored value implemented `Default` + /// (we'd still trait-bound this method). + #[inline(always)] + pub fn get_default(&self) -> Interned { + Interned { + index: 0, + _type: PhantomData, + } } } From 8e5fab6c7176edcb134e9b00d141efa32f2fe3db Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 30 Aug 2024 12:06:35 -0400 Subject: [PATCH 33/85] Fully port Optimize1qGatesDecomposition to Rust (#12959) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fully port Optimize1qGatesDecomposition to Rust This commit builds off of #12550 and the other data model in Rust infrastructure and migrates the Optimize1qGatesDecomposition pass to operate fully in Rust. The full path of the transpiler pass now never leaves rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly calibrations and parameter expressions (for global phase). But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to be a single for loop in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done by the pass so we should be able to the throughput of the pass by leveraging multithreading to handle each run in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that (this pass is a good candidate to work through the bugs on that). Part of #12208 * Tweak control_flow_op_nodes() method to avoid dag traversal when not necessary * Store target basis set without heap allocation Since we only are storing 12 enum fields (which are a single byte) using any heap allocated collection is completely overkill and will have more overhead that storing a statically sized array for all 12 variants. This commit adds a new struct that wraps a `[bool; 12]` to track which basis are supported and an API for tracking this. This simplifies the tracking of which qubit supports which EulerBasis, it also means other internal users of the 1q decomposition have a simplified API for working with the euler basis. * Remove From trait for Qubit->PhysicalQubit conversion * Fix merge conflict * Use new DAGCircuit::has_control_flow() for control_flow_op_nodes() pymethod * Move _basis_gates set creation to __init__ * Update releasenotes/notes/optimize-1q-gates-decomposition-ce111961b6782ee0.yaml Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- .../src/euler_one_qubit_decomposer.rs | 427 +++++++++++++----- crates/accelerate/src/nlayout.rs | 3 +- .../accelerate/src/target_transpiler/mod.rs | 11 + crates/accelerate/src/two_qubit_decompose.rs | 14 +- crates/circuit/src/dag_circuit.rs | 181 ++++++-- .../optimization/optimize_1q_decomposition.py | 52 +-- .../transpiler/passes/utils/control_flow.py | 10 +- ...-gates-decomposition-ce111961b6782ee0.yaml | 12 + 8 files changed, 519 insertions(+), 191 deletions(-) create mode 100644 releasenotes/notes/optimize-1q-gates-decomposition-ce111961b6782ee0.yaml diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index 75a2f7993f86..a3cb11ea45a2 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -13,7 +13,7 @@ #![allow(clippy::too_many_arguments)] #![allow(clippy::upper_case_acronyms)] -use hashbrown::HashMap; +use hashbrown::{HashMap, HashSet}; use num_complex::{Complex64, ComplexFloat}; use smallvec::{smallvec, SmallVec}; use std::cmp::Ordering; @@ -29,14 +29,19 @@ use pyo3::Python; use ndarray::prelude::*; use numpy::PyReadonlyArray2; use pyo3::pybacked::PyBackedStr; +use rustworkx_core::petgraph::stable_graph::NodeIndex; use qiskit_circuit::circuit_data::CircuitData; +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType}; use qiskit_circuit::dag_node::DAGOpNode; use qiskit_circuit::operations::{Operation, Param, StandardGate}; use qiskit_circuit::slice::{PySequenceIndex, SequenceIndex}; use qiskit_circuit::util::c64; use qiskit_circuit::Qubit; +use crate::nlayout::PhysicalQubit; +use crate::target_transpiler::Target; + pub const ANGLE_ZERO_EPSILON: f64 = 1e-12; #[pyclass(module = "qiskit._accelerate.euler_one_qubit_decomposer")] @@ -69,6 +74,7 @@ impl OneQubitGateErrorMap { } } +#[derive(Debug)] #[pyclass(sequence)] pub struct OneQubitGateSequence { pub gates: Vec<(StandardGate, SmallVec<[f64; 3]>)>, @@ -571,21 +577,116 @@ pub fn generate_circuit( Ok(res) } -#[derive(Clone, Debug, Copy)] +const EULER_BASIS_SIZE: usize = 12; + +static EULER_BASES: [&[&str]; EULER_BASIS_SIZE] = [ + &["u3"], + &["u3", "u2", "u1"], + &["u"], + &["p", "sx"], + &["u1", "rx"], + &["r"], + &["rz", "ry"], + &["rz", "rx"], + &["rz", "rx"], + &["rx", "ry"], + &["rz", "sx", "x"], + &["rz", "sx"], +]; +static EULER_BASIS_NAMES: [EulerBasis; EULER_BASIS_SIZE] = [ + EulerBasis::U3, + EulerBasis::U321, + EulerBasis::U, + EulerBasis::PSX, + EulerBasis::U1X, + EulerBasis::RR, + EulerBasis::ZYZ, + EulerBasis::ZXZ, + EulerBasis::XZX, + EulerBasis::XYX, + EulerBasis::ZSXX, + EulerBasis::ZSX, +]; + +/// A structure containing a set of supported `EulerBasis` for running 1q synthesis +#[derive(Debug, Clone)] +pub struct EulerBasisSet { + basis: [bool; EULER_BASIS_SIZE], + initialized: bool, +} + +impl EulerBasisSet { + // Instantiate a new EulerBasisSet + pub fn new() -> Self { + EulerBasisSet { + basis: [false; EULER_BASIS_SIZE], + initialized: false, + } + } + + /// Return true if this has been initialized any basis is supported + pub fn initialized(&self) -> bool { + self.initialized + } + + /// Add a basis to the set + pub fn add_basis(&mut self, basis: EulerBasis) { + self.basis[basis as usize] = true; + self.initialized = true; + } + + /// Get an iterator of all the supported EulerBasis + pub fn get_bases(&self) -> impl Iterator + '_ { + self.basis + .iter() + .enumerate() + .filter_map(|(index, supported)| { + if *supported { + Some(EULER_BASIS_NAMES[index]) + } else { + None + } + }) + } + + /// Check if a basis is supported by this set + pub fn basis_supported(&self, basis: EulerBasis) -> bool { + self.basis[basis as usize] + } + + /// Modify this set to support all EulerBasis + pub fn support_all(&mut self) { + self.basis = [true; 12]; + self.initialized = true; + } + + /// Remove an basis from the set + pub fn remove(&mut self, basis: EulerBasis) { + self.basis[basis as usize] = false; + } +} + +impl Default for EulerBasisSet { + fn default() -> Self { + Self::new() + } +} + +#[derive(Clone, Debug, Copy, Eq, Hash, PartialEq)] #[pyclass(module = "qiskit._accelerate.euler_one_qubit_decomposer")] pub enum EulerBasis { - U321, - U3, - U, - PSX, - ZSX, - ZSXX, - U1X, - RR, - ZYZ, - ZXZ, - XYX, - XZX, + U3 = 0, + U321 = 1, + U = 2, + PSX = 3, + U1X = 4, + RR = 5, + ZYZ = 6, + ZXZ = 7, + XZX = 8, + XYX = 9, + ZSXX = 10, + ZSX = 11, } impl EulerBasis { @@ -684,24 +785,6 @@ fn compare_error_fn( } } -fn compute_error( - gates: &[(StandardGate, SmallVec<[f64; 3]>)], - error_map: Option<&OneQubitGateErrorMap>, - qubit: usize, -) -> (f64, usize) { - match error_map { - Some(err_map) => { - let num_gates = gates.len(); - let gate_fidelities: f64 = gates - .iter() - .map(|gate| 1. - err_map.error_map[qubit].get(gate.0.name()).unwrap_or(&0.)) - .product(); - (1. - gate_fidelities, num_gates) - } - None => (gates.len() as f64, gates.len()), - } -} - fn compute_error_term(gate: &str, error_map: &OneQubitGateErrorMap, qubit: usize) -> f64 { 1. - error_map.error_map[qubit].get(gate).unwrap_or(&0.) } @@ -724,15 +807,6 @@ fn compute_error_str( } } -#[pyfunction] -pub fn compute_error_one_qubit_sequence( - circuit: &OneQubitGateSequence, - qubit: usize, - error_map: Option<&OneQubitGateErrorMap>, -) -> (f64, usize) { - compute_error(&circuit.gates, error_map, qubit) -} - #[pyfunction] pub fn compute_error_list( circuit: Vec>, @@ -761,13 +835,16 @@ pub fn unitary_to_gate_sequence( simplify: bool, atol: Option, ) -> PyResult> { - let target_basis_vec: PyResult> = target_basis_list + let mut target_basis_set = EulerBasisSet::new(); + for basis in target_basis_list .iter() .map(|basis| EulerBasis::__new__(basis)) - .collect(); + { + target_basis_set.add_basis(basis?); + } Ok(unitary_to_gate_sequence_inner( unitary.as_array(), - &target_basis_vec?, + &target_basis_set, qubit, error_map, simplify, @@ -778,17 +855,17 @@ pub fn unitary_to_gate_sequence( #[inline] pub fn unitary_to_gate_sequence_inner( unitary_mat: ArrayView2, - target_basis_list: &[EulerBasis], + target_basis_list: &EulerBasisSet, qubit: usize, error_map: Option<&OneQubitGateErrorMap>, simplify: bool, atol: Option, ) -> Option { target_basis_list - .iter() + .get_bases() .map(|target_basis| { - let [theta, phi, lam, phase] = angles_from_unitary(unitary_mat, *target_basis); - generate_circuit(target_basis, theta, phi, lam, phase, simplify, atol).unwrap() + let [theta, phi, lam, phase] = angles_from_unitary(unitary_mat, target_basis); + generate_circuit(&target_basis, theta, phi, lam, phase, simplify, atol).unwrap() }) .min_by(|a, b| { let error_a = compare_error_fn(a, &error_map, qubit); @@ -808,13 +885,16 @@ pub fn unitary_to_circuit( simplify: bool, atol: Option, ) -> PyResult> { - let target_basis_vec: PyResult> = target_basis_list + let mut target_basis_set = EulerBasisSet::new(); + for basis in target_basis_list .iter() .map(|basis| EulerBasis::__new__(basis)) - .collect(); + { + target_basis_set.add_basis(basis?); + } let circuit_sequence = unitary_to_gate_sequence_inner( unitary.as_array(), - &target_basis_vec?, + &target_basis_set, qubit, error_map, simplify, @@ -965,70 +1045,198 @@ pub fn params_zxz(unitary: PyReadonlyArray2) -> [f64; 4] { params_zxz_inner(mat) } -type OptimizeDecompositionReturn = Option<((f64, usize), (f64, usize), OneQubitGateSequence)>; +fn compute_error_term_from_target(gate: &str, target: &Target, qubit: PhysicalQubit) -> f64 { + 1. - target.get_error(gate, &[qubit]).unwrap_or(0.) +} + +fn compute_error_from_target_one_qubit_sequence( + circuit: &OneQubitGateSequence, + qubit: PhysicalQubit, + target: Option<&Target>, +) -> (f64, usize) { + match target { + Some(target) => { + let num_gates = circuit.gates.len(); + let gate_fidelities: f64 = circuit + .gates + .iter() + .map(|gate| compute_error_term_from_target(gate.0.name(), target, qubit)) + .product(); + (1. - gate_fidelities, num_gates) + } + None => (circuit.gates.len() as f64, circuit.gates.len()), + } +} #[pyfunction] -pub fn optimize_1q_gates_decomposition( - runs: Vec>>, - qubits: Vec, - bases: Vec>, - simplify: bool, - error_map: Option<&OneQubitGateErrorMap>, - atol: Option, -) -> Vec { - runs.iter() - .enumerate() - .map(|(index, raw_run)| -> OptimizeDecompositionReturn { - let mut error = match error_map { - Some(_) => 1., - None => raw_run.len() as f64, +#[pyo3(signature = (dag, *, target=None, basis_gates=None, global_decomposers=None))] +pub(crate) fn optimize_1q_gates_decomposition( + py: Python, + dag: &mut DAGCircuit, + target: Option<&Target>, + basis_gates: Option>, + global_decomposers: Option>, +) -> PyResult<()> { + let runs: Vec> = dag.collect_1q_runs().unwrap().collect(); + let dag_qubits = dag.num_qubits(); + let mut target_basis_per_qubit: Vec = vec![EulerBasisSet::new(); dag_qubits]; + let mut basis_gates_per_qubit: Vec>> = vec![None; dag_qubits]; + for raw_run in runs { + let mut error = match target { + Some(_) => 1., + None => raw_run.len() as f64, + }; + let qubit: PhysicalQubit = if let NodeType::Operation(inst) = &dag.dag[raw_run[0]] { + PhysicalQubit::new(dag.get_qargs(inst.qubits)[0].0) + } else { + unreachable!("nodes in runs will always be op nodes") + }; + if !dag.calibrations_empty() { + let mut has_calibration = false; + for node in &raw_run { + if dag.has_calibration_for_index(py, *node)? { + has_calibration = true; + break; + } + } + if has_calibration { + continue; + } + } + if basis_gates_per_qubit[qubit.0 as usize].is_none() { + let basis_gates = match target { + Some(target) => Some( + target + .operation_names_for_qargs(Some(&smallvec![qubit])) + .unwrap(), + ), + None => { + let basis = basis_gates.as_ref(); + basis.map(|basis| basis.iter().map(|x| x.as_str()).collect()) + } }; - let qubit = qubits[index]; - let operator = &raw_run - .iter() - .map(|node| { - if let Some(err_map) = error_map { - error *= - compute_error_term(node.instruction.operation.name(), err_map, qubit) - } - node.instruction - .operation - .matrix(&node.instruction.params) - .expect("No matrix defined for operation") - }) - .fold( - [ - [Complex64::new(1., 0.), Complex64::new(0., 0.)], - [Complex64::new(0., 0.), Complex64::new(1., 0.)], - ], - |mut operator, node| { - matmul_1q(&mut operator, node); - operator + basis_gates_per_qubit[qubit.0 as usize] = basis_gates; + } + let basis_gates = &basis_gates_per_qubit[qubit.0 as usize].as_ref(); + + let target_basis_set = &mut target_basis_per_qubit[qubit.0 as usize]; + if !target_basis_set.initialized() { + match target { + Some(_target) => EULER_BASES + .iter() + .enumerate() + .filter_map(|(idx, gates)| { + if !gates + .iter() + .all(|gate| basis_gates.as_ref().unwrap().contains(gate)) + { + return None; + } + let basis = EULER_BASIS_NAMES[idx]; + Some(basis) + }) + .for_each(|basis| target_basis_set.add_basis(basis)), + None => match &global_decomposers { + Some(bases) => bases + .iter() + .map(|basis| EulerBasis::__new__(basis).unwrap()) + .for_each(|basis| target_basis_set.add_basis(basis)), + None => match basis_gates { + Some(gates) => EULER_BASES + .iter() + .enumerate() + .filter_map(|(idx, basis_gates)| { + if !gates.iter().all(|gate| basis_gates.as_ref().contains(gate)) { + return None; + } + let basis = EULER_BASIS_NAMES[idx]; + Some(basis) + }) + .for_each(|basis| target_basis_set.add_basis(basis)), + None => target_basis_set.support_all(), }, - ); - let old_error = if error_map.is_some() { - (1. - error, raw_run.len()) - } else { - (error, raw_run.len()) + }, }; - let target_basis_vec: Vec = bases[index] - .iter() - .map(|basis| EulerBasis::__new__(basis).unwrap()) - .collect(); - unitary_to_gate_sequence_inner( - aview2(operator), - &target_basis_vec, - qubit, - error_map, - simplify, - atol, - ) - .map(|out_seq| { - let new_error = compute_error_one_qubit_sequence(&out_seq, qubit, error_map); - (old_error, new_error, out_seq) + if target_basis_set.basis_supported(EulerBasis::U3) + && target_basis_set.basis_supported(EulerBasis::U321) + { + target_basis_set.remove(EulerBasis::U3); + } + if target_basis_set.basis_supported(EulerBasis::ZSX) + && target_basis_set.basis_supported(EulerBasis::ZSXX) + { + target_basis_set.remove(EulerBasis::ZSX); + } + } + let target_basis_set = &target_basis_per_qubit[qubit.0 as usize]; + let operator = raw_run + .iter() + .map(|node_index| { + let node = &dag.dag[*node_index]; + if let NodeType::Operation(inst) = node { + if let Some(target) = target { + error *= compute_error_term_from_target(inst.op.name(), target, qubit); + } + inst.op.matrix(inst.params_view()).unwrap() + } else { + unreachable!("Can only have op nodes here") + } }) - }) - .collect() + .fold( + [ + [Complex64::new(1., 0.), Complex64::new(0., 0.)], + [Complex64::new(0., 0.), Complex64::new(1., 0.)], + ], + |mut operator, node| { + matmul_1q(&mut operator, node); + operator + }, + ); + + let old_error = if target.is_some() { + (1. - error, raw_run.len()) + } else { + (error, raw_run.len()) + }; + let sequence = unitary_to_gate_sequence_inner( + aview2(&operator), + target_basis_set, + qubit.0 as usize, + None, + true, + None, + ); + let sequence = match sequence { + Some(seq) => seq, + None => continue, + }; + let new_error = compute_error_from_target_one_qubit_sequence(&sequence, qubit, target); + + let mut outside_basis = false; + if let Some(basis) = basis_gates { + for node in &raw_run { + if let NodeType::Operation(inst) = &dag.dag[*node] { + if !basis.contains(inst.op.name()) { + outside_basis = true; + break; + } + } + } + } else { + outside_basis = false; + } + if outside_basis + || new_error < old_error + || new_error.0.abs() < 1e-9 && old_error.0.abs() >= 1e-9 + { + for gate in sequence.gates { + dag.insert_1q_on_incoming_qubit((gate.0, &gate.1), raw_run[0]); + } + dag.add_global_phase(py, &Param::Float(sequence.global_phase))?; + dag.remove_1q_sequence(&raw_run); + } + } + Ok(()) } fn matmul_1q(operator: &mut [[Complex64; 2]; 2], other: Array2) { @@ -1054,7 +1262,6 @@ pub fn euler_one_qubit_decomposer(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(generate_circuit))?; m.add_wrapped(wrap_pyfunction!(unitary_to_gate_sequence))?; m.add_wrapped(wrap_pyfunction!(unitary_to_circuit))?; - m.add_wrapped(wrap_pyfunction!(compute_error_one_qubit_sequence))?; m.add_wrapped(wrap_pyfunction!(compute_error_list))?; m.add_wrapped(wrap_pyfunction!(optimize_1q_gates_decomposition))?; m.add_class::()?; diff --git a/crates/accelerate/src/nlayout.rs b/crates/accelerate/src/nlayout.rs index e0235e5c954a..93b1036b608e 100644 --- a/crates/accelerate/src/nlayout.rs +++ b/crates/accelerate/src/nlayout.rs @@ -24,7 +24,7 @@ use hashbrown::HashMap; macro_rules! qubit_newtype { ($id: ident) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct $id(u32); + pub struct $id(pub u32); impl $id { #[inline] @@ -72,6 +72,7 @@ impl PhysicalQubit { layout.phys_to_virt[self.index()] } } + qubit_newtype!(VirtualQubit); impl VirtualQubit { /// Get the physical qubit that currently corresponds to this index of virtual qubit in the diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index 6d6e105b265d..08b3e90eabba 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -940,6 +940,17 @@ impl Target { }); } + /// Get the error rate of a given instruction in the target + pub fn get_error(&self, name: &str, qargs: &[PhysicalQubit]) -> Option { + self.gate_map.get(name).and_then(|gate_props| { + let qargs_key: Qargs = qargs.iter().cloned().collect(); + match gate_props.get(Some(&qargs_key)) { + Some(props) => props.as_ref().and_then(|inst_props| inst_props.error), + None => None, + } + }) + } + /// Get an iterator over the indices of all physical qubits of the target pub fn physical_qubits(&self) -> impl ExactSizeIterator { 0..self.num_qubits.unwrap_or_default() diff --git a/crates/accelerate/src/two_qubit_decompose.rs b/crates/accelerate/src/two_qubit_decompose.rs index 77ebb3f9433c..2c745b199e9e 100644 --- a/crates/accelerate/src/two_qubit_decompose.rs +++ b/crates/accelerate/src/two_qubit_decompose.rs @@ -41,7 +41,7 @@ use pyo3::types::PyList; use crate::convert_2q_block_matrix::change_basis; use crate::euler_one_qubit_decomposer::{ - angles_from_unitary, det_one_qubit, unitary_to_gate_sequence_inner, EulerBasis, + angles_from_unitary, det_one_qubit, unitary_to_gate_sequence_inner, EulerBasis, EulerBasisSet, OneQubitGateSequence, ANGLE_ZERO_EPSILON, }; use crate::utils; @@ -1060,7 +1060,8 @@ impl TwoQubitWeylDecomposition { Some(basis) => EulerBasis::__new__(basis.deref())?, None => self.default_euler_basis, }; - let target_1q_basis_list: Vec = vec![euler_basis]; + let mut target_1q_basis_list = EulerBasisSet::new(); + target_1q_basis_list.add_basis(euler_basis); let mut gate_sequence = CircuitData::with_capacity(py, 2, 0, 21, Param::Float(0.))?; let mut global_phase: f64 = self.global_phase; @@ -1507,7 +1508,8 @@ impl TwoQubitBasisDecomposer { unitary: ArrayView2, qubit: u8, ) { - let target_1q_basis_list = vec![self.euler_basis]; + let mut target_1q_basis_list = EulerBasisSet::new(); + target_1q_basis_list.add_basis(self.euler_basis); let sequence = unitary_to_gate_sequence_inner( unitary, &target_1q_basis_list, @@ -1751,7 +1753,8 @@ impl TwoQubitBasisDecomposer { if let Some(seq) = sequence { return Ok(seq); } - let target_1q_basis_list = vec![self.euler_basis]; + let mut target_1q_basis_list = EulerBasisSet::new(); + target_1q_basis_list.add_basis(self.euler_basis); let euler_decompositions: SmallVec<[Option; 8]> = decomposition .iter() .map(|decomp| { @@ -1993,7 +1996,8 @@ impl TwoQubitBasisDecomposer { if let Some(seq) = sequence { return Ok(seq); } - let target_1q_basis_list = vec![self.euler_basis]; + let mut target_1q_basis_list = EulerBasisSet::new(); + target_1q_basis_list.add_basis(self.euler_basis); let euler_decompositions: SmallVec<[Option; 8]> = decomposition .iter() .map(|decomp| { diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index b6e33e78c1b2..afe6797596d9 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -22,8 +22,8 @@ use crate::dag_node::{DAGInNode, DAGNode, DAGOpNode, DAGOutNode}; use crate::dot_utils::build_dot; use crate::error::DAGCircuitError; use crate::imports; -use crate::interner::Interner; -use crate::operations::{Operation, OperationRef, Param, PyInstruction}; +use crate::interner::{Interned, Interner}; +use crate::operations::{Operation, OperationRef, Param, PyInstruction, StandardGate}; use crate::packed_instruction::PackedInstruction; use crate::rustworkx_core_vnext::isomorphism; use crate::{BitType, Clbit, Qubit, TupleLikeArg}; @@ -3867,7 +3867,7 @@ def _format(operand): /// include_directives (bool): include `barrier`, `snapshot` etc. /// /// Returns: - /// list[DAGOpNode]: the list of node ids containing the given op. + /// list[DAGOpNode]: the list of dag nodes containing the given op. #[pyo3(name= "op_nodes", signature=(op=None, include_directives=true))] fn py_op_nodes( &self, @@ -3903,6 +3903,33 @@ def _format(operand): Ok(nodes) } + /// Get a list of "op" nodes in the dag that contain control flow instructions. + /// + /// Returns: + /// list[DAGOpNode] | None: The list of dag nodes containing control flow ops. If there + /// are no control flow nodes None is returned + fn control_flow_op_nodes(&self, py: Python) -> PyResult>>> { + if self.has_control_flow() { + let result: PyResult>> = self + .dag + .node_references() + .filter_map(|(node_index, node_type)| match node_type { + NodeType::Operation(ref node) => { + if node.op.control_flow() { + Some(self.unpack_into(py, node_index, node_type)) + } else { + None + } + } + _ => None, + }) + .collect(); + Ok(Some(result?)) + } else { + Ok(None) + } + } + /// Get the list of gate nodes in the dag. /// /// Returns: @@ -4978,31 +5005,6 @@ def _format(operand): Ok(result) } - fn _insert_1q_on_incoming_qubit( - &mut self, - py: Python, - node: &Bound, - old_index: usize, - ) -> PyResult<()> { - if let NodeType::Operation(inst) = self.pack_into(py, node)? { - self.increment_op(inst.op.name()); - let new_index = self.dag.add_node(NodeType::Operation(inst)); - let old_index: NodeIndex = NodeIndex::new(old_index); - let (parent_index, edge_index, weight) = self - .dag - .edges_directed(old_index, Incoming) - .map(|edge| (edge.source(), edge.id(), edge.weight().clone())) - .next() - .unwrap(); - self.dag.add_edge(parent_index, new_index, weight.clone()); - self.dag.add_edge(new_index, old_index, weight); - self.dag.remove_edge(edge_index); - Ok(()) - } else { - Err(PyTypeError::new_err("Invalid node type input")) - } - } - fn _edges(&self, py: Python) -> Vec { self.dag .edge_indices() @@ -5604,7 +5606,7 @@ impl DAGCircuit { /// Remove an operation node n. /// /// Add edges from predecessors to successors. - fn remove_op_node(&mut self, index: NodeIndex) { + pub fn remove_op_node(&mut self, index: NodeIndex) { let mut edge_list: Vec<(NodeIndex, NodeIndex, Wire)> = Vec::new(); for (source, in_weight) in self .dag @@ -6154,6 +6156,127 @@ impl DAGCircuit { } Ok(()) } + /// Get qargs from an intern index + pub fn get_qargs(&self, index: Interned<[Qubit]>) -> &[Qubit] { + self.qargs_interner.get(index) + } + + /// Get cargs from an intern index + pub fn get_cargs(&self, index: Interned<[Clbit]>) -> &[Clbit] { + self.cargs_interner.get(index) + } + + /// Insert a new 1q standard gate on incoming qubit + pub fn insert_1q_on_incoming_qubit( + &mut self, + new_gate: (StandardGate, &[f64]), + old_index: NodeIndex, + ) { + self.increment_op(new_gate.0.name()); + let old_node = &self.dag[old_index]; + let inst = if let NodeType::Operation(old_node) = old_node { + PackedInstruction { + op: new_gate.0.into(), + qubits: old_node.qubits, + clbits: old_node.clbits, + params: (!new_gate.1.is_empty()) + .then(|| Box::new(new_gate.1.iter().map(|x| Param::Float(*x)).collect())), + extra_attrs: None, + #[cfg(feature = "cache_pygates")] + py_op: OnceCell::new(), + } + } else { + panic!("This method only works if provided index is an op node"); + }; + let new_index = self.dag.add_node(NodeType::Operation(inst)); + let (parent_index, edge_index, weight) = self + .dag + .edges_directed(old_index, Incoming) + .map(|edge| (edge.source(), edge.id(), edge.weight().clone())) + .next() + .unwrap(); + self.dag.add_edge(parent_index, new_index, weight.clone()); + self.dag.add_edge(new_index, old_index, weight); + self.dag.remove_edge(edge_index); + } + + /// Remove a sequence of 1 qubit nodes from the dag + /// This must only be called if all the nodes operate + /// on a single qubit with no other wires in or out of any nodes + pub fn remove_1q_sequence(&mut self, sequence: &[NodeIndex]) { + let (parent_index, weight) = self + .dag + .edges_directed(*sequence.first().unwrap(), Incoming) + .map(|edge| (edge.source(), edge.weight().clone())) + .next() + .unwrap(); + let child_index = self + .dag + .edges_directed(*sequence.last().unwrap(), Outgoing) + .map(|edge| edge.target()) + .next() + .unwrap(); + self.dag.add_edge(parent_index, child_index, weight); + for node in sequence { + match self.dag.remove_node(*node) { + Some(NodeType::Operation(packed)) => { + let op_name = packed.op.name(); + self.decrement_op(op_name); + } + _ => panic!("Must be called with valid operation node!"), + } + } + } + + pub fn add_global_phase(&mut self, py: Python, value: &Param) -> PyResult<()> { + match value { + Param::Obj(_) => { + return Err(PyTypeError::new_err( + "Invalid parameter type, only float and parameter expression are supported", + )) + } + _ => self.set_global_phase(add_global_phase(py, &self.global_phase, value)?)?, + } + Ok(()) + } + + pub fn calibrations_empty(&self) -> bool { + self.calibrations.is_empty() + } + + pub fn has_calibration_for_index(&self, py: Python, node_index: NodeIndex) -> PyResult { + let node = &self.dag[node_index]; + if let NodeType::Operation(instruction) = node { + if !self.calibrations.contains_key(instruction.op.name()) { + return Ok(false); + } + let params = match &instruction.params { + Some(params) => { + let mut out_params = Vec::new(); + for p in params.iter() { + if let Param::ParameterExpression(exp) = p { + let exp = exp.bind(py); + if !exp.getattr(intern!(py, "parameters"))?.is_truthy()? { + let as_py_float = exp.call_method0(intern!(py, "__float__"))?; + out_params.push(as_py_float.unbind()); + continue; + } + } + out_params.push(p.to_object(py)); + } + PyTuple::new_bound(py, out_params) + } + None => PyTuple::empty_bound(py), + }; + let qargs = self.qargs_interner.get(instruction.qubits); + let qubits = PyTuple::new_bound(py, qargs.iter().map(|x| x.0)); + self.calibrations[instruction.op.name()] + .bind(py) + .contains((qubits, params).to_object(py)) + } else { + Err(DAGCircuitError::new_err("Specified node is not an op node")) + } + } } /// Add to global phase. Global phase can only be Float or ParameterExpression so this diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py index 181f02e312b3..ac7673060746 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py @@ -35,7 +35,6 @@ from qiskit.circuit import Qubit from qiskit.circuit.quantumcircuitdata import CircuitInstruction from qiskit.dagcircuit.dagcircuit import DAGCircuit -from qiskit.dagcircuit.dagnode import DAGOpNode logger = logging.getLogger(__name__) @@ -82,9 +81,12 @@ def __init__(self, basis=None, target=None): """ super().__init__() - self._basis_gates = basis + if basis: + self._basis_gates = set(basis) + else: + self._basis_gates = None self._target = target - self._global_decomposers = [] + self._global_decomposers = None self._local_decomposers_cache = {} if basis: @@ -209,46 +211,12 @@ def run(self, dag): Returns: DAGCircuit: the optimized DAG. """ - runs = [] - qubits = [] - bases = [] - for run in dag.collect_1q_runs(): - qubit = dag.find_bit(run[0].qargs[0]).index - runs.append(run) - qubits.append(qubit) - bases.append(self._get_decomposer(qubit)) - best_sequences = euler_one_qubit_decomposer.optimize_1q_gates_decomposition( - runs, qubits, bases, simplify=True, error_map=self.error_map + euler_one_qubit_decomposer.optimize_1q_gates_decomposition( + dag, + target=self._target, + global_decomposers=self._global_decomposers, + basis_gates=self._basis_gates, ) - for index, best_circuit_sequence in enumerate(best_sequences): - run = runs[index] - qubit = qubits[index] - if self._target is None: - basis = self._basis_gates - else: - basis = self._target.operation_names_for_qargs((qubit,)) - if best_circuit_sequence is not None: - (old_error, new_error, best_circuit_sequence) = best_circuit_sequence - if self._substitution_checks( - dag, - run, - best_circuit_sequence, - basis, - qubit, - old_error=old_error, - new_error=new_error, - ): - first_node_id = run[0]._node_id - qubit = run[0].qargs - for gate, angles in best_circuit_sequence: - op = CircuitInstruction.from_standard(gate, qubit, angles) - node = DAGOpNode.from_instruction(op) - dag._insert_1q_on_incoming_qubit(node, first_node_id) - dag.global_phase += best_circuit_sequence.global_phase - # Delete the other nodes in the run - for current_node in run: - dag.remove_op_node(current_node) - return dag def _error(self, circuit, qubit): diff --git a/qiskit/transpiler/passes/utils/control_flow.py b/qiskit/transpiler/passes/utils/control_flow.py index 27c3c83d53c7..4fc95587e782 100644 --- a/qiskit/transpiler/passes/utils/control_flow.py +++ b/qiskit/transpiler/passes/utils/control_flow.py @@ -54,10 +54,12 @@ def out(self, dag): def bound_wrapped_method(dag): return out(self, dag) - for node in dag.op_nodes(ControlFlowOp): - dag.substitute_node( - node, map_blocks(bound_wrapped_method, node.op), propagate_condition=False - ) + control_flow_nodes = dag.control_flow_op_nodes() + if control_flow_nodes is not None: + for node in control_flow_nodes: + dag.substitute_node( + node, map_blocks(bound_wrapped_method, node.op), propagate_condition=False + ) return method(self, dag) return out diff --git a/releasenotes/notes/optimize-1q-gates-decomposition-ce111961b6782ee0.yaml b/releasenotes/notes/optimize-1q-gates-decomposition-ce111961b6782ee0.yaml new file mode 100644 index 000000000000..dbb095827b00 --- /dev/null +++ b/releasenotes/notes/optimize-1q-gates-decomposition-ce111961b6782ee0.yaml @@ -0,0 +1,12 @@ +--- +features_transpiler: + - | + Added a new method :meth:`.DAGCircuit.control_flow_ops` which provides a fast + path to get all the :class:`.DAGOpNode` in a :class:`.DAGCircuit` that + contain a :class:`.ControlFlowOp`. This was possible before using the + :meth:`.DAGCircuit.op_nodes` method and passing the :class:`.ControlFlowOp` class + as a filter, but this new function will perform the operation faster. + - | + Ported the entirety of the :class:`.Optimize1qGatesDecomposition` transpiler + pass to Rust. This improves the runtime performance of the pass between 5x + to 10x. From 623415cdb740fd6e164f0f5fd2b55fba081cd437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= <57907331+ElePT@users.noreply.github.com> Date: Fri, 30 Aug 2024 21:10:26 +0200 Subject: [PATCH 34/85] Fix use of `node.op` in `Split2QUnitaries` (#13015) * Replace node.op with node.matrix * Add docstring to test gate * Fix black --- .../passes/optimization/split_2q_unitaries.py | 2 +- ...nitaries-custom-gate-d10f7670a35548f4.yaml | 6 +++ .../transpiler/test_split_2q_unitaries.py | 39 ++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-split-2q-unitaries-custom-gate-d10f7670a35548f4.yaml diff --git a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py index ac04043a27fa..0b1788e5bbe6 100644 --- a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py +++ b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py @@ -51,7 +51,7 @@ def run(self, dag: DAGCircuit): ): continue - decomp = TwoQubitWeylDecomposition(node.op, fidelity=self.requested_fidelity) + decomp = TwoQubitWeylDecomposition(node.matrix, fidelity=self.requested_fidelity) if ( decomp._inner_decomposition.specialization == TwoQubitWeylDecomposition._specializations.IdEquiv diff --git a/releasenotes/notes/fix-split-2q-unitaries-custom-gate-d10f7670a35548f4.yaml b/releasenotes/notes/fix-split-2q-unitaries-custom-gate-d10f7670a35548f4.yaml new file mode 100644 index 000000000000..331156cf6012 --- /dev/null +++ b/releasenotes/notes/fix-split-2q-unitaries-custom-gate-d10f7670a35548f4.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed a bug in :class:`.Split2QUnitaries` where it would fail to run on circuits + with custom gates that didn't implement :meth:`__array__`. + See `#12984 `__. \ No newline at end of file diff --git a/test/python/transpiler/test_split_2q_unitaries.py b/test/python/transpiler/test_split_2q_unitaries.py index 616d93e5b3f8..7fbb93c2419d 100644 --- a/test/python/transpiler/test_split_2q_unitaries.py +++ b/test/python/transpiler/test_split_2q_unitaries.py @@ -19,7 +19,7 @@ from qiskit import QuantumCircuit, QuantumRegister, transpile from qiskit.circuit.library import UnitaryGate, XGate, ZGate, HGate -from qiskit.circuit import Parameter, CircuitInstruction +from qiskit.circuit import Parameter, CircuitInstruction, Gate from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.quantum_info import Operator from qiskit.transpiler import PassManager @@ -223,3 +223,40 @@ def test_split_qft(self): pm.append(Split2QUnitaries()) qc_split = pm.run(qc) self.assertEqual(26, qc_split.num_nonlocal_gates()) + + def test_gate_no_array(self): + """ + Test that the pass doesn't fail when the circuit contains a custom gate + with no ``__array__`` implementation. + + Reproduce from: https://github.com/Qiskit/qiskit/issues/12970 + """ + + class MyGate(Gate): + """Custom gate""" + + def __init__(self): + super().__init__("mygate", 2, []) + + def to_matrix(self): + return np.eye(4, dtype=complex) + # return np.eye(4, dtype=float) + + def mygate(self, qubit1, qubit2): + return self.append(MyGate(), [qubit1, qubit2], []) + + QuantumCircuit.mygate = mygate + + qc = QuantumCircuit(2) + qc.mygate(0, 1) + + pm = PassManager() + pm.append(Collect2qBlocks()) + pm.append(ConsolidateBlocks()) + pm.append(Split2QUnitaries()) + qc_split = pm.run(qc) + + self.assertTrue(Operator(qc).equiv(qc_split)) + self.assertTrue( + matrix_equal(Operator(qc).data, Operator(qc_split).data, ignore_phase=False) + ) From 5fc1635b6c447e910dbf9f390eb1e6ec789e70a4 Mon Sep 17 00:00:00 2001 From: melechlapson Date: Fri, 30 Aug 2024 16:55:00 -0500 Subject: [PATCH 35/85] Port the count_ops method in QuantumCircuit to Rust (#13050) * added get_ops method to CircuitData Rust class * Updated count_ops method in QuantumCircuit * remove extra indexmap dependency * fixed linting issues * moved import * removed return statement * updated method names * added release note * add blank line * revert changes to Cargo.lock * removed unnecessary features * Apply suggestions from Matthew's review Co-authored-by: Matthew Treinish * added docstring to count_ops method * Update crates/circuit/src/circuit_data.rs Co-authored-by: Matthew Treinish --------- Co-authored-by: Matthew Treinish --- crates/circuit/src/circuit_data.rs | 17 +++++++++++++++++ qiskit/circuit/quantumcircuit.py | 6 ++---- .../port-countops-method-3ad362c20b13182c.yaml | 5 +++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/port-countops-method-3ad362c20b13182c.yaml diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 1aed43de0a21..da49f9edc605 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -31,6 +31,7 @@ use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyTuple, PyType}; use pyo3::{import_exception, intern, PyTraverseError, PyVisit}; use hashbrown::{HashMap, HashSet}; +use indexmap::IndexMap; use smallvec::SmallVec; import_exception!(qiskit.circuit.exceptions, CircuitError); @@ -983,6 +984,22 @@ impl CircuitData { self.param_table.clear(); } + /// Counts the number of times each operation is used in the circuit. + /// + /// # Parameters + /// - `self` - A mutable reference to the CircuitData struct. + /// + /// # Returns + /// An IndexMap containing the operation names as keys and their respective counts as values. + pub fn count_ops(&self) -> IndexMap<&str, usize, ::ahash::RandomState> { + let mut ops_count: IndexMap<&str, usize, ::ahash::RandomState> = IndexMap::default(); + for instruction in &self.data { + *ops_count.entry(instruction.op.name()).or_insert(0) += 1; + } + ops_count.par_sort_by(|_k1, v1, _k2, v2| v2.cmp(v1)); + ops_count + } + // Marks this pyclass as NOT hashable. #[classattr] const __hash__: Option> = None; diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 487f1e28e382..ebc63511ca7b 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -3516,10 +3516,8 @@ def count_ops(self) -> "OrderedDict[Instruction, int]": Returns: OrderedDict: a breakdown of how many operations of each kind, sorted by amount. """ - count_ops: dict[Instruction, int] = {} - for instruction in self._data: - count_ops[instruction.operation.name] = count_ops.get(instruction.operation.name, 0) + 1 - return OrderedDict(sorted(count_ops.items(), key=lambda kv: kv[1], reverse=True)) + ops_dict = self._data.count_ops() + return OrderedDict(ops_dict) def num_nonlocal_gates(self) -> int: """Return number of non-local gates (i.e. involving 2+ qubits). diff --git a/releasenotes/notes/port-countops-method-3ad362c20b13182c.yaml b/releasenotes/notes/port-countops-method-3ad362c20b13182c.yaml new file mode 100644 index 000000000000..93a92fa4c316 --- /dev/null +++ b/releasenotes/notes/port-countops-method-3ad362c20b13182c.yaml @@ -0,0 +1,5 @@ +--- +features_circuits: + - | + The :meth:`~.QuantumCircuit.count_ops` method in :class:`.QuantumCircuit` + has been re-written in Rust. It now runs between 3 and 9 times faster. From f4ca088644b4461b856b4b49c33e23b04a995019 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:14:16 +0000 Subject: [PATCH 36/85] Bump indexmap from 2.4.0 to 2.5.0 (#13068) Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.4.0 to 2.5.0. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.4.0...2.5.0) --- updated-dependencies: - dependency-name: indexmap dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 136ca4bed376..10344e611726 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,9 +570,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", diff --git a/Cargo.toml b/Cargo.toml index a35a87d4d3b1..4f7f8ad86b96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ license = "Apache-2.0" # Each crate can add on specific features freely as it inherits. [workspace.dependencies] bytemuck = "1.17" -indexmap.version = "2.4.0" +indexmap.version = "2.5.0" hashbrown.version = "0.14.5" num-bigint = "0.4" num-complex = "0.4" From 3fac5da41e2aba66e5d0735e9e9e8159b9ba24f2 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 2 Sep 2024 17:08:20 +0200 Subject: [PATCH 37/85] docs: ensure CollectAndCollapse is part of the public API (#13071) --- qiskit/transpiler/passes/__init__.py | 2 ++ qiskit/transpiler/passes/optimization/__init__.py | 1 + 2 files changed, 3 insertions(+) diff --git a/qiskit/transpiler/passes/__init__.py b/qiskit/transpiler/passes/__init__.py index 1feabeaef048..ca4e3545a98b 100644 --- a/qiskit/transpiler/passes/__init__.py +++ b/qiskit/transpiler/passes/__init__.py @@ -71,6 +71,7 @@ Collect1qRuns Collect2qBlocks CollectMultiQBlocks + CollectAndCollapse CollectLinearFunctions CollectCliffords ConsolidateBlocks @@ -238,6 +239,7 @@ from .optimization import TemplateOptimization from .optimization import InverseCancellation from .optimization import EchoRZXWeylDecomposition +from .optimization import CollectAndCollapse from .optimization import CollectLinearFunctions from .optimization import CollectCliffords from .optimization import ResetAfterMeasureSimplification diff --git a/qiskit/transpiler/passes/optimization/__init__.py b/qiskit/transpiler/passes/optimization/__init__.py index a9796850a689..8e2883b27781 100644 --- a/qiskit/transpiler/passes/optimization/__init__.py +++ b/qiskit/transpiler/passes/optimization/__init__.py @@ -39,3 +39,4 @@ from .normalize_rx_angle import NormalizeRXAngle from .optimize_annotated import OptimizeAnnotated from .split_2q_unitaries import Split2QUnitaries +from .collect_and_collapse import CollectAndCollapse From f30f851c98fdc7369d1d710937438c13d0e13f08 Mon Sep 17 00:00:00 2001 From: Shravan Patel <78003234+shravanpatel30@users.noreply.github.com> Date: Tue, 3 Sep 2024 02:51:38 -0500 Subject: [PATCH 38/85] Fixed ZZFeatureMap not accepting a list of entanglement (#12767) * Added a get_entangler_map() and _selective_entangler_map() functions to PauliFeatureMap * Added some logic to handle the List[List[List[List[int]]]] case. Refer to the comments in the code. * `entanglement` can now be specified as dictionary `{num_qubits: entanglement}` * Added logic to handle cases when entanglement is not specified for some pauli blocks. * Added tests cases for `PauliFeatureMap` * Added test and releasenotes. Also modified the typing hints and doc strings to reflect new changes. * Replaced all tab characters with spaces to fix the linting error. * Formatted releasenotes as per the suggestion to fix the issue in reno. * Added `Callable[[int], Union[str | Dict[...]]]` to the typing hints and included some logic to handle that. * Removed `List[List[int]]` from typing hints as this is equivalent to List[Tuple[int]] Co-authored-by: Julien Gacon * updated the release notes Co-authored-by: Julien Gacon * Updated typing hints in `ZZFeatureMap` --------- Co-authored-by: Julien Gacon --- .../data_preparation/pauli_feature_map.py | 57 +++++++++++++-- .../data_preparation/zz_feature_map.py | 10 ++- ...nary-as-entanglement-02037cb2d46e1c41.yaml | 26 +++++++ .../circuit/library/test_pauli_feature_map.py | 73 +++++++++++++++++++ 4 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/paulifeaturemap-takes-dictionary-as-entanglement-02037cb2d46e1c41.yaml diff --git a/qiskit/circuit/library/data_preparation/pauli_feature_map.py b/qiskit/circuit/library/data_preparation/pauli_feature_map.py index 03bbc031ec63..8cad7d23835b 100644 --- a/qiskit/circuit/library/data_preparation/pauli_feature_map.py +++ b/qiskit/circuit/library/data_preparation/pauli_feature_map.py @@ -11,8 +11,7 @@ # that they have been altered from the originals. """The Pauli expansion circuit module.""" - -from typing import Optional, Callable, List, Union +from typing import Optional, Callable, List, Union, Sequence, Dict, Tuple from functools import reduce import numpy as np @@ -116,7 +115,11 @@ def __init__( self, feature_dimension: Optional[int] = None, reps: int = 2, - entanglement: Union[str, List[List[int]], Callable[[int], List[int]]] = "full", + entanglement: Union[ + str, + Dict[int, List[Tuple[int]]], + Callable[[int], Union[str, Dict[int, List[Tuple[int]]]]], + ] = "full", alpha: float = 2.0, paulis: Optional[List[str]] = None, data_map_func: Optional[Callable[[np.ndarray], float]] = None, @@ -129,8 +132,13 @@ def __init__( Args: feature_dimension: Number of qubits in the circuit. reps: The number of repeated circuits. - entanglement: Specifies the entanglement structure. Refer to - :class:`~qiskit.circuit.library.NLocal` for detail. + entanglement: Specifies the entanglement structure. Can be a string (``'full'``, + ``'linear'``, ``'reverse_linear'``, ``'circular'`` or ``'sca'``) or can be a + dictionary where the keys represent the number of qubits and the values are list + of integer-pairs specifying the indices of qubits that are entangled with one + another, for example: ``{1: [(0,), (2,)], 2: [(0,1), (2,0)]}`` or can be a + ``Callable[[int], Union[str | Dict[...]]]`` to return an entanglement specific for + a repetition alpha: The Pauli rotation factor, multiplicative to the pauli rotations paulis: A list of strings for to-be-used paulis. If None are provided, ``['Z', 'ZZ']`` will be used. @@ -281,6 +289,45 @@ def cx_chain(circuit, inverse=False): basis_change(evo, inverse=True) return evo + def get_entangler_map( + self, rep_num: int, block_num: int, num_block_qubits: int + ) -> Sequence[Sequence[int]]: + + # if entanglement is a Callable[[int], Union[str | Dict[...]]] + if callable(self._entanglement): + entanglement = self._entanglement(rep_num) + else: + entanglement = self._entanglement + + # entanglement is Dict[int, List[List[int]]] + if isinstance(entanglement, dict): + if all( + isinstance(e2, (int, np.int32, np.int64)) + for key in entanglement.keys() + for en in entanglement[key] + for e2 in en + ): + for qb, ent in entanglement.items(): + for en in ent: + if len(en) != qb: + raise ValueError( + f"For num_qubits = {qb}, entanglement must be a " + f"tuple of length {qb}. You specified {en}." + ) + + # Check if the entanglement is specified for all the pauli blocks being used + for pauli in self.paulis: + if len(pauli) not in entanglement.keys(): + raise ValueError(f"No entanglement specified for {pauli} pauli.") + + return entanglement[num_block_qubits] + + else: + # if the entanglement is not Dict[int, List[List[int]]] or + # Dict[int, List[Tuple[int]]] then we fall back on the original + # `get_entangler_map()` method from NLocal + return super().get_entangler_map(rep_num, block_num, num_block_qubits) + def self_product(x: np.ndarray) -> float: """ diff --git a/qiskit/circuit/library/data_preparation/zz_feature_map.py b/qiskit/circuit/library/data_preparation/zz_feature_map.py index 5500bb6691be..2f51b8f63482 100644 --- a/qiskit/circuit/library/data_preparation/zz_feature_map.py +++ b/qiskit/circuit/library/data_preparation/zz_feature_map.py @@ -12,7 +12,7 @@ """Second-order Pauli-Z expansion circuit.""" -from typing import Callable, List, Union, Optional +from typing import Callable, List, Union, Optional, Dict, Tuple import numpy as np from .pauli_feature_map import PauliFeatureMap @@ -75,7 +75,11 @@ def __init__( self, feature_dimension: int, reps: int = 2, - entanglement: Union[str, List[List[int]], Callable[[int], List[int]]] = "full", + entanglement: Union[ + str, + Dict[int, List[Tuple[int]]], + Callable[[int], Union[str, Dict[int, List[Tuple[int]]]]], + ] = "full", data_map_func: Optional[Callable[[np.ndarray], float]] = None, parameter_prefix: str = "x", insert_barriers: bool = False, @@ -87,7 +91,7 @@ def __init__( feature_dimension: Number of features. reps: The number of repeated circuits, has a min. value of 1. entanglement: Specifies the entanglement structure. Refer to - :class:`~qiskit.circuit.library.NLocal` for detail. + :class:`~qiskit.circuit.library.PauliFeatureMap` for detail. data_map_func: A mapping function for data x. parameter_prefix: The prefix used if default parameters are generated. insert_barriers: If True, barriers are inserted in between the evolution instructions diff --git a/releasenotes/notes/paulifeaturemap-takes-dictionary-as-entanglement-02037cb2d46e1c41.yaml b/releasenotes/notes/paulifeaturemap-takes-dictionary-as-entanglement-02037cb2d46e1c41.yaml new file mode 100644 index 000000000000..8acfe5439a50 --- /dev/null +++ b/releasenotes/notes/paulifeaturemap-takes-dictionary-as-entanglement-02037cb2d46e1c41.yaml @@ -0,0 +1,26 @@ +--- +fixes: + - | + Fixed that the entanglement in :class:`.PauliFeatureMap` and :class:`.ZZFeatureMap` + could be given as ``List[int]`` or ``List[List[int]]``, which was incompatible with the fact + that entanglement blocks of different sizes are used. Instead, the entanglement can be + given as dictionary with ``{block_size: entanglement}`` pairs. +features_circuits: + - | + :class:`.PauliFeatureMap` and :class:`.ZZFeatureMap` now support specifying the + entanglement as a dictionary where the keys represent the number of qubits, and + the values are lists of integer tuples that define which qubits are entangled with one another. This + allows for more flexibility in constructing feature maps tailored to specific quantum algorithms. + Example usage:: + + from qiskit.circuit.library import PauliFeatureMap + entanglement = { + 1: [(0,), (2,)], + 2: [(0, 1), (1, 2)], + 3: [(0, 1, 2)], + } + qc = PauliFeatureMap(3, reps=2, paulis=['Z', 'ZZ', 'ZZZ'], entanglement=entanglement, insert_barriers=True) + qc.decompose().draw('mpl') + + + diff --git a/test/python/circuit/library/test_pauli_feature_map.py b/test/python/circuit/library/test_pauli_feature_map.py index 60b7e5c28b9c..0e15af654edd 100644 --- a/test/python/circuit/library/test_pauli_feature_map.py +++ b/test/python/circuit/library/test_pauli_feature_map.py @@ -221,6 +221,79 @@ def test_parameter_prefix(self): self.assertEqual(str(encoding_z_param_y.parameters), "ParameterView([Parameter(y)])") self.assertEqual(str(encoding_zz_param_y.parameters), "ParameterView([Parameter(y)])") + def test_entanglement_as_dictionary(self): + """Test whether PauliFeatureMap accepts entanglement as a dictionary and generates + correct feature map circuit""" + n_qubits = 3 + entanglement = { + 1: [(0,), (2,)], + 2: [(0, 1), (1, 2)], + 3: [(0, 1, 2)], + } + params = [np.pi / 4, np.pi / 2, np.pi] + + def z_block(circuit, q1): + circuit.p(2 * params[q1], q1) + + def zz_block(circuit, q1, q2): + param = (np.pi - params[q1]) * (np.pi - params[q2]) + circuit.cx(q1, q2) + circuit.p(2 * param, q2) + circuit.cx(q1, q2) + + def zzz_block(circuit, q1, q2, q3): + param = (np.pi - params[q1]) * (np.pi - params[q2]) * (np.pi - params[q3]) + circuit.cx(q1, q2) + circuit.cx(q2, q3) + circuit.p(2 * param, q3) + circuit.cx(q2, q3) + circuit.cx(q1, q2) + + feat_map = PauliFeatureMap( + n_qubits, reps=2, paulis=["Z", "ZZ", "ZZZ"], entanglement=entanglement + ).assign_parameters(params) + + qc = QuantumCircuit(n_qubits) + for _ in range(2): + qc.h([0, 1, 2]) + for e1 in entanglement[1]: + z_block(qc, *e1) + for e2 in entanglement[2]: + zz_block(qc, *e2) + for e3 in entanglement[3]: + zzz_block(qc, *e3) + + self.assertTrue(Operator(feat_map).equiv(qc)) + + def test_invalid_entanglement(self): + """Test if a ValueError is raised when an invalid entanglement is passed""" + n_qubits = 3 + entanglement = { + 1: [(0, 1), (2,)], + 2: [(0, 1), (1, 2)], + 3: [(0, 1, 2)], + } + + with self.assertRaises(ValueError): + feat_map = PauliFeatureMap( + n_qubits, reps=2, paulis=["Z", "ZZ", "ZZZ"], entanglement=entanglement + ) + feat_map.count_ops() + + def test_entanglement_not_specified(self): + """Test if an error is raised when entanglement is not explicitly specified for + all n-qubit pauli blocks""" + n_qubits = 3 + entanglement = { + 1: [(0, 1), (2,)], + 3: [(0, 1, 2)], + } + with self.assertRaises(ValueError): + feat_map = PauliFeatureMap( + n_qubits, reps=2, paulis=["Z", "ZZ", "ZZZ"], entanglement=entanglement + ) + feat_map.count_ops() + if __name__ == "__main__": unittest.main() From f882fd53d3903b002ebc97b2b23bc8a70200763e Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Tue, 3 Sep 2024 14:10:01 +0300 Subject: [PATCH 39/85] Oxidize random clifford (#12695) * starting to experiment * porting code * messy code porting * printing statements to enable debugging * fixes * fixing phase * removing some of the printing statements * fixing inaccuracy for cost computation * Moving some of the functionality to SymplecticMatrix class * reducing the number of warnings * formatting * replacing expensive adjoint and compose operations for symplectic matrices by significantly cheaper in-place prepend operations * resolving merge conflicts * cleanup * code cleanup * cleanup * cleanup * cleanup * cleanup * cleanup * cleanup * cleanup * using fast lookup * cleanup * clippy * including params in gate_seq to avoid mapping * removing unnecessary inner function * cleanup * renaming * changes on the python side * reno * adding error handling * improved error handling * removing redundant Ok(Some(...)) * using random_clifford in tests * reorganizing clifford code * fixes * formatting * improved error handling * do not panic * formatting * initial implementation * cleanup * changing return to be the full tableau * parallelized computation for binary matrix multiplication for matrices with >= 10 qubits * updating python code and adding release notes * lint, test, reno * removing obsolete python code * removing todo (after experimenting with alternative implementation) * removing another obsolete todo * unused import * adding comment --- .../accelerate/src/synthesis/clifford/mod.rs | 26 ++- .../src/synthesis/clifford/random_clifford.rs | 162 ++++++++++++++++++ .../accelerate/src/synthesis/linear/utils.rs | 51 +++++- .../operators/symplectic/random.py | 156 +---------------- ...dize-random-clifford-934f45876c14c8a0.yaml | 5 + .../operators/symplectic/test_clifford.py | 4 +- 6 files changed, 243 insertions(+), 161 deletions(-) create mode 100644 crates/accelerate/src/synthesis/clifford/random_clifford.rs create mode 100644 releasenotes/notes/oxidize-random-clifford-934f45876c14c8a0.yaml diff --git a/crates/accelerate/src/synthesis/clifford/mod.rs b/crates/accelerate/src/synthesis/clifford/mod.rs index 4828a5666734..d2c1e36fab4f 100644 --- a/crates/accelerate/src/synthesis/clifford/mod.rs +++ b/crates/accelerate/src/synthesis/clifford/mod.rs @@ -12,12 +12,13 @@ mod bm_synthesis; mod greedy_synthesis; +mod random_clifford; mod utils; use crate::synthesis::clifford::bm_synthesis::synth_clifford_bm_inner; use crate::synthesis::clifford::greedy_synthesis::GreedyCliffordSynthesis; use crate::QiskitError; -use numpy::PyReadonlyArray2; +use numpy::{IntoPyArray, PyArray2, PyReadonlyArray2}; use pyo3::prelude::*; use qiskit_circuit::circuit_data::CircuitData; use qiskit_circuit::operations::Param; @@ -43,6 +44,28 @@ fn synth_clifford_greedy(py: Python, clifford: PyReadonlyArray2) -> PyResu CircuitData::from_standard_gates(py, num_qubits as u32, clifford_gates, Param::Float(0.0)) } +/// Generate a random Clifford tableau. +/// +/// The Clifford is sampled using the method of the paper "Hadamard-free circuits +/// expose the structure of the Clifford group" by S. Bravyi and D. Maslov (2020), +/// `https://arxiv.org/abs/2003.09412`__. +/// +/// Args: +/// num_qubits: the number of qubits. +/// seed: an optional random seed. +/// Returns: +/// result: a random clifford tableau. +#[pyfunction] +#[pyo3(signature = (num_qubits, seed=None))] +fn random_clifford_tableau( + py: Python, + num_qubits: usize, + seed: Option, +) -> PyResult>> { + let tableau = random_clifford::random_clifford_tableau_inner(num_qubits, seed); + Ok(tableau.into_pyarray_bound(py).unbind()) +} + /// Create a circuit that optimally synthesizes a given Clifford operator represented as /// a tableau for Cliffords up to 3 qubits. /// @@ -60,5 +83,6 @@ fn synth_clifford_bm(py: Python, clifford: PyReadonlyArray2) -> PyResult) -> PyResult<()> { m.add_function(wrap_pyfunction!(synth_clifford_greedy, m)?)?; m.add_function(wrap_pyfunction!(synth_clifford_bm, m)?)?; + m.add_function(wrap_pyfunction!(random_clifford_tableau, m)?)?; Ok(()) } diff --git a/crates/accelerate/src/synthesis/clifford/random_clifford.rs b/crates/accelerate/src/synthesis/clifford/random_clifford.rs new file mode 100644 index 000000000000..fee3ac8e9650 --- /dev/null +++ b/crates/accelerate/src/synthesis/clifford/random_clifford.rs @@ -0,0 +1,162 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use crate::synthesis::linear::utils::{ + binary_matmul_inner, calc_inverse_matrix_inner, replace_row_inner, swap_rows_inner, +}; +use ndarray::{concatenate, s, Array1, Array2, ArrayView2, ArrayViewMut2, Axis}; +use rand::{Rng, SeedableRng}; +use rand_pcg::Pcg64Mcg; + +/// Sample from the quantum Mallows distribution. +fn sample_qmallows(n: usize, rng: &mut Pcg64Mcg) -> (Array1, Array1) { + // Hadamard layer + let mut had = Array1::from_elem(n, false); + + // Permutation layer + let mut perm = Array1::from_elem(n, 0); + let mut inds: Vec = (0..n).collect(); + + for i in 0..n { + let m = n - i; + let eps: f64 = 4f64.powi(-(m as i32)); + let r: f64 = rng.gen(); + let index: usize = -((r + (1f64 - r) * eps).log2().ceil() as isize) as usize; + had[i] = index < m; + let k = if index < m { index } else { 2 * m - index - 1 }; + perm[i] = inds[k]; + inds.remove(k); + } + (had, perm) +} + +/// Add symmetric random boolean value to off diagonal entries. +fn fill_tril(mut mat: ArrayViewMut2, rng: &mut Pcg64Mcg, symmetric: bool) { + let n = mat.shape()[0]; + for i in 0..n { + for j in 0..i { + mat[[i, j]] = rng.gen(); + if symmetric { + mat[[j, i]] = mat[[i, j]]; + } + } + } +} + +/// Invert a lower-triangular matrix with unit diagonal. +fn inverse_tril(mat: ArrayView2) -> Array2 { + calc_inverse_matrix_inner(mat, false).unwrap() +} + +/// Generate a random Clifford tableau. +/// +/// The Clifford is sampled using the method of the paper "Hadamard-free circuits +/// expose the structure of the Clifford group" by S. Bravyi and D. Maslov (2020), +/// `https://arxiv.org/abs/2003.09412`__. +/// +/// The function returns a random clifford tableau. +pub fn random_clifford_tableau_inner(num_qubits: usize, seed: Option) -> Array2 { + let mut rng = match seed { + Some(seed) => Pcg64Mcg::seed_from_u64(seed), + None => Pcg64Mcg::from_entropy(), + }; + + let (had, perm) = sample_qmallows(num_qubits, &mut rng); + + let mut gamma1: Array2 = Array2::from_elem((num_qubits, num_qubits), false); + for i in 0..num_qubits { + gamma1[[i, i]] = rng.gen(); + } + fill_tril(gamma1.view_mut(), &mut rng, true); + + let mut gamma2: Array2 = Array2::from_elem((num_qubits, num_qubits), false); + for i in 0..num_qubits { + gamma2[[i, i]] = rng.gen(); + } + fill_tril(gamma2.view_mut(), &mut rng, true); + + let mut delta1: Array2 = Array2::from_shape_fn((num_qubits, num_qubits), |(i, j)| i == j); + fill_tril(delta1.view_mut(), &mut rng, false); + + let mut delta2: Array2 = Array2::from_shape_fn((num_qubits, num_qubits), |(i, j)| i == j); + fill_tril(delta2.view_mut(), &mut rng, false); + + // Compute stabilizer table + let zero = Array2::from_elem((num_qubits, num_qubits), false); + let prod1 = binary_matmul_inner(gamma1.view(), delta1.view()).unwrap(); + let prod2 = binary_matmul_inner(gamma2.view(), delta2.view()).unwrap(); + let inv1 = inverse_tril(delta1.view()).t().to_owned(); + let inv2 = inverse_tril(delta2.view()).t().to_owned(); + + let table1 = concatenate( + Axis(0), + &[ + concatenate(Axis(1), &[delta1.view(), zero.view()]) + .unwrap() + .view(), + concatenate(Axis(1), &[prod1.view(), inv1.view()]) + .unwrap() + .view(), + ], + ) + .unwrap(); + + let table2 = concatenate( + Axis(0), + &[ + concatenate(Axis(1), &[delta2.view(), zero.view()]) + .unwrap() + .view(), + concatenate(Axis(1), &[prod2.view(), inv2.view()]) + .unwrap() + .view(), + ], + ) + .unwrap(); + + // Compute the full stabilizer tableau + + // The code below is identical to the Python implementation, but is based on the original + // code in the paper. + + let mut table = Array2::from_elem((2 * num_qubits, 2 * num_qubits), false); + + // Apply qubit permutation + for i in 0..num_qubits { + replace_row_inner(table.view_mut(), i, table2.slice(s![i, ..])); + replace_row_inner( + table.view_mut(), + perm[i] + num_qubits, + table2.slice(s![perm[i] + num_qubits, ..]), + ); + } + + // Apply layer of Hadamards + for i in 0..num_qubits { + if had[i] { + swap_rows_inner(table.view_mut(), i, i + num_qubits); + } + } + + // Apply table + let random_symplectic_mat = binary_matmul_inner(table1.view(), table.view()).unwrap(); + + // Generate random phases + let random_phases: Array2 = Array2::from_shape_fn((2 * num_qubits, 1), |_| rng.gen()); + + let random_tableau: Array2 = concatenate( + Axis(1), + &[random_symplectic_mat.view(), random_phases.view()], + ) + .unwrap(); + random_tableau +} diff --git a/crates/accelerate/src/synthesis/linear/utils.rs b/crates/accelerate/src/synthesis/linear/utils.rs index b4dbf4993081..5f1fb99fa682 100644 --- a/crates/accelerate/src/synthesis/linear/utils.rs +++ b/crates/accelerate/src/synthesis/linear/utils.rs @@ -10,9 +10,17 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -use ndarray::{concatenate, s, Array2, ArrayView2, ArrayViewMut2, Axis}; +use ndarray::{azip, concatenate, s, Array2, ArrayView1, ArrayView2, ArrayViewMut2, Axis, Zip}; use rand::{Rng, SeedableRng}; use rand_pcg::Pcg64Mcg; +use rayon::iter::{IndexedParallelIterator, ParallelIterator}; +use rayon::prelude::IntoParallelIterator; + +use crate::getenv_use_multiple_threads; + +/// Specifies the minimum number of qubits in order to parallelize computations +/// (this number is chosen based on several local experiments). +const PARALLEL_THRESHOLD: usize = 10; /// Binary matrix multiplication pub fn binary_matmul_inner( @@ -30,11 +38,29 @@ pub fn binary_matmul_inner( )); } - Ok(Array2::from_shape_fn((n1_rows, n2_cols), |(i, j)| { - (0..n2_rows) - .map(|k| mat1[[i, k]] & mat2[[k, j]]) - .fold(false, |acc, v| acc ^ v) - })) + let run_in_parallel = getenv_use_multiple_threads(); + + if n1_rows < PARALLEL_THRESHOLD || !run_in_parallel { + Ok(Array2::from_shape_fn((n1_rows, n2_cols), |(i, j)| { + (0..n2_rows) + .map(|k| mat1[[i, k]] & mat2[[k, j]]) + .fold(false, |acc, v| acc ^ v) + })) + } else { + let mut result = Array2::from_elem((n1_rows, n2_cols), false); + result + .axis_iter_mut(Axis(0)) + .into_par_iter() + .enumerate() + .for_each(|(i, mut row)| { + for j in 0..n2_cols { + row[j] = (0..n2_rows) + .map(|k| mat1[[i, k]] & mat2[[k, j]]) + .fold(false, |acc, v| acc ^ v) + } + }); + Ok(result) + } } /// Gauss elimination of a matrix mat with m rows and n columns. @@ -198,3 +224,16 @@ pub fn check_invertible_binary_matrix_inner(mat: ArrayView2) -> bool { let rank = compute_rank_inner(mat); rank == mat.nrows() } + +/// Mutate matrix ``mat`` in-place by swapping the contents of rows ``i`` and ``j``. +pub fn swap_rows_inner(mut mat: ArrayViewMut2, i: usize, j: usize) { + let (mut x, mut y) = mat.multi_slice_mut((s![i, ..], s![j, ..])); + azip!((x in &mut x, y in &mut y) (*x, *y) = (*y, *x)); +} + +/// Mutate matrix ``mat`` in-place by replacing the contents of row ``i`` by ``row``. +pub fn replace_row_inner(mut mat: ArrayViewMut2, i: usize, row: ArrayView1) { + let mut x = mat.slice_mut(s![i, ..]); + let y = row.slice(s![..]); + Zip::from(&mut x).and(&y).for_each(|x, &y| *x = y); +} diff --git a/qiskit/quantum_info/operators/symplectic/random.py b/qiskit/quantum_info/operators/symplectic/random.py index 06b23ca29803..848bce73aa35 100644 --- a/qiskit/quantum_info/operators/symplectic/random.py +++ b/qiskit/quantum_info/operators/symplectic/random.py @@ -14,11 +14,12 @@ """ from __future__ import annotations -import math import numpy as np from numpy.random import default_rng +from qiskit._accelerate.synthesis.clifford import random_clifford_tableau + from .clifford import Clifford from .pauli import Pauli from .pauli_list import PauliList @@ -111,155 +112,6 @@ def random_clifford(num_qubits: int, seed: int | np.random.Generator | None = No else: rng = default_rng(seed) - had, perm = _sample_qmallows(num_qubits, rng) - - gamma1 = np.diag(rng.integers(2, size=num_qubits, dtype=np.int8)) - gamma2 = np.diag(rng.integers(2, size=num_qubits, dtype=np.int8)) - delta1 = np.eye(num_qubits, dtype=np.int8) - delta2 = delta1.copy() - - _fill_tril(gamma1, rng, symmetric=True) - _fill_tril(gamma2, rng, symmetric=True) - _fill_tril(delta1, rng) - _fill_tril(delta2, rng) - - # For large num_qubits numpy.inv function called below can - # return invalid output leading to a non-symplectic Clifford - # being generated. This can be prevented by manually forcing - # block inversion of the matrix. - block_inverse_threshold = 50 - - # Compute stabilizer table - zero = np.zeros((num_qubits, num_qubits), dtype=np.int8) - prod1 = np.matmul(gamma1, delta1) % 2 - prod2 = np.matmul(gamma2, delta2) % 2 - inv1 = _inverse_tril(delta1, block_inverse_threshold).transpose() - inv2 = _inverse_tril(delta2, block_inverse_threshold).transpose() - table1 = np.block([[delta1, zero], [prod1, inv1]]) - table2 = np.block([[delta2, zero], [prod2, inv2]]) - - # Apply qubit permutation - table = table2[np.concatenate([perm, num_qubits + perm])] - - # Apply layer of Hadamards - inds = had * np.arange(1, num_qubits + 1) - inds = inds[inds > 0] - 1 - lhs_inds = np.concatenate([inds, inds + num_qubits]) - rhs_inds = np.concatenate([inds + num_qubits, inds]) - table[lhs_inds, :] = table[rhs_inds, :] - - # Apply table - tableau = np.zeros((2 * num_qubits, 2 * num_qubits + 1), dtype=bool) - tableau[:, :-1] = np.mod(np.matmul(table1, table), 2) - - # Generate random phases - tableau[:, -1] = rng.integers(2, size=2 * num_qubits) + seed = rng.integers(100000, size=1, dtype=np.uint64)[0] + tableau = random_clifford_tableau(num_qubits, seed=seed) return Clifford(tableau, validate=False) - - -def _sample_qmallows(n, rng=None): - """Sample from the quantum Mallows distribution""" - - if rng is None: - rng = np.random.default_rng() - - # Hadamard layer - had = np.zeros(n, dtype=bool) - - # Permutation layer - perm = np.zeros(n, dtype=int) - - inds = list(range(n)) - for i in range(n): - m = n - i - eps = 4 ** (-m) - r = rng.uniform(0, 1) - index = -math.ceil(math.log2(r + (1 - r) * eps)) - had[i] = index < m - if index < m: - k = index - else: - k = 2 * m - index - 1 - perm[i] = inds[k] - del inds[k] - return had, perm - - -def _fill_tril(mat, rng, symmetric=False): - """Add symmetric random ints to off diagonals""" - dim = mat.shape[0] - # Optimized for low dimensions - if dim == 1: - return - - if dim <= 4: - mat[1, 0] = rng.integers(2, dtype=np.int8) - if symmetric: - mat[0, 1] = mat[1, 0] - if dim > 2: - mat[2, 0] = rng.integers(2, dtype=np.int8) - mat[2, 1] = rng.integers(2, dtype=np.int8) - if symmetric: - mat[0, 2] = mat[2, 0] - mat[1, 2] = mat[2, 1] - if dim > 3: - mat[3, 0] = rng.integers(2, dtype=np.int8) - mat[3, 1] = rng.integers(2, dtype=np.int8) - mat[3, 2] = rng.integers(2, dtype=np.int8) - if symmetric: - mat[0, 3] = mat[3, 0] - mat[1, 3] = mat[3, 1] - mat[2, 3] = mat[3, 2] - return - - # Use numpy indices for larger dimensions - rows, cols = np.tril_indices(dim, -1) - vals = rng.integers(2, size=rows.size, dtype=np.int8) - mat[(rows, cols)] = vals - if symmetric: - mat[(cols, rows)] = vals - - -def _inverse_tril(mat, block_inverse_threshold): - """Invert a lower-triangular matrix with unit diagonal.""" - # Optimized inversion function for low dimensions - dim = mat.shape[0] - - if dim <= 2: - return mat - - if dim <= 5: - inv = mat.copy() - inv[2, 0] = mat[2, 0] ^ (mat[1, 0] & mat[2, 1]) - if dim > 3: - inv[3, 1] = mat[3, 1] ^ (mat[2, 1] & mat[3, 2]) - inv[3, 0] = mat[3, 0] ^ (mat[3, 2] & mat[2, 0]) ^ (mat[1, 0] & inv[3, 1]) - if dim > 4: - inv[4, 2] = (mat[4, 2] ^ (mat[3, 2] & mat[4, 3])) & 1 - inv[4, 1] = mat[4, 1] ^ (mat[4, 3] & mat[3, 1]) ^ (mat[2, 1] & inv[4, 2]) - inv[4, 0] = ( - mat[4, 0] - ^ (mat[1, 0] & inv[4, 1]) - ^ (mat[2, 0] & inv[4, 2]) - ^ (mat[3, 0] & mat[4, 3]) - ) - return inv % 2 - - # For higher dimensions we use Numpy's inverse function - # however this function tends to fail and result in a non-symplectic - # final matrix if n is too large. - if dim <= block_inverse_threshold: - return np.linalg.inv(mat).astype(np.int8) % 2 - - # For very large matrices we divide the matrix into 4 blocks of - # roughly equal size and use the analytic formula for the inverse - # of a block lower-triangular matrix: - # inv([[A, 0],[C, D]]) = [[inv(A), 0], [inv(D).C.inv(A), inv(D)]] - # call the inverse function recursively to compute inv(A) and invD - - dim1 = dim // 2 - mat_a = _inverse_tril(mat[0:dim1, 0:dim1], block_inverse_threshold) - mat_d = _inverse_tril(mat[dim1:dim, dim1:dim], block_inverse_threshold) - mat_c = np.matmul(np.matmul(mat_d, mat[dim1:dim, 0:dim1]), mat_a) - inv = np.block([[mat_a, np.zeros((dim1, dim - dim1), dtype=int)], [mat_c, mat_d]]) - return inv % 2 diff --git a/releasenotes/notes/oxidize-random-clifford-934f45876c14c8a0.yaml b/releasenotes/notes/oxidize-random-clifford-934f45876c14c8a0.yaml new file mode 100644 index 000000000000..236ad441992d --- /dev/null +++ b/releasenotes/notes/oxidize-random-clifford-934f45876c14c8a0.yaml @@ -0,0 +1,5 @@ +--- +features_synthesis: + - | + The function :func:`~qiskit.quantum_info.random_clifford` was ported to Rust, + improving the runtime by a factor of 3. diff --git a/test/python/quantum_info/operators/symplectic/test_clifford.py b/test/python/quantum_info/operators/symplectic/test_clifford.py index 36d716d2d85a..061348c78cdb 100644 --- a/test/python/quantum_info/operators/symplectic/test_clifford.py +++ b/test/python/quantum_info/operators/symplectic/test_clifford.py @@ -492,8 +492,8 @@ def test_from_circuit_with_all_types(self): # Additionally, make sure that it produces the correct clifford. expected_clifford_dict = { - "stabilizer": ["-IZX", "+ZYZ", "+ZII"], - "destabilizer": ["+ZIZ", "+ZXZ", "-XIX"], + "stabilizer": ["-IZX", "+XXZ", "-YYZ"], + "destabilizer": ["-YYI", "-XZI", "-ZXY"], } expected_clifford = Clifford.from_dict(expected_clifford_dict) self.assertEqual(combined_clifford, expected_clifford) From b501db1e218817abc353f150011b4f2e79e53b1f Mon Sep 17 00:00:00 2001 From: tglanz Date: Tue, 3 Sep 2024 16:35:31 +0300 Subject: [PATCH 40/85] skip test unless HAS_PIL (#13077) --- test/python/visualization/test_dag_drawer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/python/visualization/test_dag_drawer.py b/test/python/visualization/test_dag_drawer.py index d789b1e70682..56138c12cf00 100644 --- a/test/python/visualization/test_dag_drawer.py +++ b/test/python/visualization/test_dag_drawer.py @@ -46,6 +46,7 @@ def test_dag_drawer_invalid_style(self): dag_drawer(self.dag, style="multicolor") @unittest.skipUnless(_optionals.HAS_GRAPHVIZ, "Graphviz not installed") + @unittest.skipUnless(_optionals.HAS_PIL, "PIL not installed") def test_dag_drawer_checks_filename_correct_format(self): """filename must contain name and extension""" with self.assertRaisesRegex( From df0ad77fd592aae2ad071bcd9160b181b915172d Mon Sep 17 00:00:00 2001 From: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:37:57 +0200 Subject: [PATCH 41/85] Oxidize commutation checker (#12870) * init * up * lint * . * up * before cache * with cache * correct * cleaned up * lint reno * Update Cargo.lock * . * up * . * revert op * . * . * . * . * Delete Cargo.lock * . * corrected string comparison * removed Operator class from operation.rs * . * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * comments from code review * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * code review * remove with_gil in favor of passing python tokens as params * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * fmt * python serialization * deprecation * Update commutation_checker.py * heh * let Pytuple collect * lint * First set of comments - use Qubit/Clbit - more info on unsafe - update reno - use LazySet less - use OperationRef, avoid CircuitInstruction creation * Second part - clippy - no BigInt - more comments * Matrix speed & fix string sort -- could not use op.name() directly since sorted differently than Python, hence it's back to BigInt * have the Python implementation use Rust * lint & tools * remove unsafe blocks * One more try to avoid segfaulty windows -- if that doesn't work maybe revert the change the the Py CommChecker uses Rust * Debug: disable cache trying to figure out why the windows CI fails (after being unable to locally reproduce we're using CI with a reduced set of tests) * ... second try * Update crates/accelerate/src/commutation_checker.rs Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * Restore azure config * Remove unused import * Revert "Debug: disable cache" This reverts commit c564b806c9ff31d5faa6aa3f02c18cfe6a5ff2c5. * Don't overallocate cache We were allocating a the cache hashmap with a capacity for max cache size entries every time we instantiated a new CommutationChecker. The max cache size is 1 million. This meant we were allocating 162MB everytime CommutationChecker.__new__ was called, which includes each time we instantiate it manually (which happens once on import), the CommutationAnalysis pass gets instantiated (twice per preset pass manager created with level 2 or 3), or a commutation checker instance is pickle deserialized. This ends up causing a fairly large memory regression and is the source of the CI failures on windows. Co-authored-by: Jake Lishman * Cleanup parameter key type to handle edge conditions better This commit cleans up the ParameterKey type and usage to make it handle edge conditions better. The first is that the type just doesn't do the right thing for NaN, -0, or the infinities. Canonicalization is added for hash on -0 and the only constructor of the newtype adds a runtime guard against NaN and inifinity (positive or negative) to avoid that issue. The approach only makes sense as the cache is really there to guard us against unnecessary re-computing when we reiterate over the circuit > 1 time and nothing has changed for gates. Otherwise comparing floats like done in this PR does would not be a sound or an effective approach. * Remove unnecessary cache hit rate tracking * Undo test assertion changes * Undo unrelated test changes * Undo pending deprecation and unify commutation classes This commit removes the pending deprecation decorator from the python class definition as the Python class just internally is using the rust implementation now. This also removes directly using the rust implementation for the standard commutation library global as using the python class is exactly the same now. We can revisit if there is anything we want to deprecate and remove in 2.0 in a follow up PR. Personally, I think the cache management methods are all we really want to remove as the cache should be an internal implementation detail and not part of the public interface. * Undo gha config changes * Make serialization explicit This commit makes the pickling of cache entries explicit. Previously it was relying on conversion traits which hid some of the complexity but this uses a pair of conversion functions instead. * Remove stray SAFETY comment * Remove ddt usage from the tests Now that the python commutation checker and the rust commutation checker are the same thing the ddt parameterization of the commutation checker tests was unecessary duplication. This commit removes the ddt usage to restore having a single run of all the tests. * Update release note * Fix CommutationChecker class import * Remove invalid test assertion for no longer public attribute * Ray's review comments Co-authored-by: Raynel Sanchez * Handle ``atol/rtol``, more error propagation * re-use expensive quantities such as the relative placement and the parameter hash --------- Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Co-authored-by: Matthew Treinish Co-authored-by: Julien Gacon Co-authored-by: Jake Lishman Co-authored-by: Raynel Sanchez --- Cargo.lock | 74 +- crates/accelerate/Cargo.toml | 2 + crates/accelerate/src/commutation_checker.rs | 775 ++++++++++++++++++ crates/accelerate/src/lib.rs | 2 + crates/accelerate/src/unitary_compose.rs | 240 ++++++ crates/pyext/src/lib.rs | 18 +- qiskit/__init__.py | 1 + qiskit/circuit/commutation_checker.py | 396 +-------- .../commutative_inverse_cancellation.py | 13 +- ...-commutation-checker-c738e67efa9d292f.yaml | 6 + .../circuit/test_commutation_checker.py | 309 +++---- tools/build_standard_commutations.py | 60 +- 12 files changed, 1287 insertions(+), 609 deletions(-) create mode 100644 crates/accelerate/src/commutation_checker.rs create mode 100644 crates/accelerate/src/unitary_compose.rs create mode 100644 releasenotes/notes/rust-commutation-checker-c738e67efa9d292f.yaml diff --git a/Cargo.lock b/Cargo.lock index 10344e611726..7921b7aeba83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.18" @@ -41,6 +50,15 @@ dependencies = [ "log", ] +[[package]] +name = "approx" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] + [[package]] name = "approx" version = "0.5.1" @@ -629,6 +647,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.154" @@ -783,7 +807,8 @@ version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" dependencies = [ - "approx", + "approx 0.4.0", + "approx 0.5.1", "matrixmultiply", "num-complex", "num-integer", @@ -792,6 +817,18 @@ dependencies = [ "rayon", ] +[[package]] +name = "ndarray_einsum_beta" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b3abeae3e0637740340e0e32a9bf9308380e146ea6797950f9ff16e88d88a" +dependencies = [ + "lazy_static", + "ndarray", + "num-traits", + "regex", +] + [[package]] name = "npyz" version = "0.8.3" @@ -1180,17 +1217,19 @@ name = "qiskit-accelerate" version = "1.3.0" dependencies = [ "ahash 0.8.11", - "approx", + "approx 0.5.1", "faer", "faer-ext", "hashbrown 0.14.5", "indexmap", "itertools 0.13.0", "ndarray", + "ndarray_einsum_beta", "num-bigint", "num-complex", "num-traits", "numpy", + "once_cell", "pulp", "pyo3", "qiskit-circuit", @@ -1208,7 +1247,7 @@ name = "qiskit-circuit" version = "1.3.0" dependencies = [ "ahash 0.8.11", - "approx", + "approx 0.5.1", "bytemuck", "hashbrown 0.14.5", "indexmap", @@ -1394,6 +1433,35 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rowan" version = "0.15.15" diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index 3248e61e29ac..f444a5c8ed66 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -24,6 +24,8 @@ faer = "0.19.2" itertools.workspace = true qiskit-circuit.workspace = true thiserror.workspace = true +ndarray_einsum_beta = "0.7" +once_cell = "1.19.0" [dependencies.smallvec] workspace = true diff --git a/crates/accelerate/src/commutation_checker.rs b/crates/accelerate/src/commutation_checker.rs new file mode 100644 index 000000000000..6fd9d58a7c23 --- /dev/null +++ b/crates/accelerate/src/commutation_checker.rs @@ -0,0 +1,775 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use hashbrown::{HashMap, HashSet}; +use ndarray::linalg::kron; +use ndarray::Array2; +use num_complex::Complex64; +use once_cell::sync::Lazy; +use smallvec::SmallVec; + +use numpy::PyReadonlyArray2; +use pyo3::exceptions::PyRuntimeError; +use pyo3::intern; +use pyo3::prelude::*; +use pyo3::types::{IntoPyDict, PyBool, PyDict, PySequence, PyTuple}; + +use qiskit_circuit::bit_data::BitData; +use qiskit_circuit::circuit_instruction::{ExtraInstructionAttributes, OperationFromPython}; +use qiskit_circuit::dag_node::DAGOpNode; +use qiskit_circuit::imports::QI_OPERATOR; +use qiskit_circuit::operations::OperationRef::{Gate as PyGateType, Operation as PyOperationType}; +use qiskit_circuit::operations::{Operation, OperationRef, Param}; +use qiskit_circuit::{BitType, Clbit, Qubit}; + +use crate::unitary_compose; +use crate::QiskitError; + +static SKIPPED_NAMES: [&str; 4] = ["measure", "reset", "delay", "initialize"]; +static NO_CACHE_NAMES: [&str; 2] = ["annotated", "linear_function"]; +static SUPPORTED_OP: Lazy> = Lazy::new(|| { + HashSet::from([ + "h", "x", "y", "z", "sx", "sxdg", "t", "tdg", "s", "sdg", "cx", "cy", "cz", "swap", + "iswap", "ecr", "ccx", "cswap", + ]) +}); + +fn get_bits( + py: Python, + bits1: &Bound, + bits2: &Bound, +) -> PyResult<(Vec, Vec)> +where + T: From + Copy, + BitType: From, +{ + let mut bitdata: BitData = BitData::new(py, "bits".to_string()); + + for bit in bits1.iter().chain(bits2.iter()) { + bitdata.add(py, &bit, false)?; + } + + Ok(( + bitdata.map_bits(bits1)?.collect(), + bitdata.map_bits(bits2)?.collect(), + )) +} + +/// This is the internal structure for the Python CommutationChecker class +/// It handles the actual commutation checking, cache management, and library +/// lookups. It's not meant to be a public facing Python object though and only used +/// internally by the Python class. +#[pyclass(module = "qiskit._accelerate.commutation_checker")] +struct CommutationChecker { + library: CommutationLibrary, + cache_max_entries: usize, + cache: HashMap<(String, String), CommutationCacheEntry>, + current_cache_entries: usize, + #[pyo3(get)] + gates: Option>, +} + +#[pymethods] +impl CommutationChecker { + #[pyo3(signature = (standard_gate_commutations=None, cache_max_entries=1_000_000, gates=None))] + #[new] + fn py_new( + standard_gate_commutations: Option>, + cache_max_entries: usize, + gates: Option>, + ) -> Self { + // Initialize sets before they are used in the commutation checker + Lazy::force(&SUPPORTED_OP); + CommutationChecker { + library: CommutationLibrary::new(standard_gate_commutations), + cache: HashMap::new(), + cache_max_entries, + current_cache_entries: 0, + gates, + } + } + + #[pyo3(signature=(op1, op2, max_num_qubits=3))] + fn commute_nodes( + &mut self, + py: Python, + op1: &DAGOpNode, + op2: &DAGOpNode, + max_num_qubits: u32, + ) -> PyResult { + let (qargs1, qargs2) = get_bits::( + py, + op1.instruction.qubits.bind(py), + op2.instruction.qubits.bind(py), + )?; + let (cargs1, cargs2) = get_bits::( + py, + op1.instruction.clbits.bind(py), + op2.instruction.clbits.bind(py), + )?; + + self.commute_inner( + py, + &op1.instruction.operation.view(), + &op1.instruction.params, + op1.instruction.extra_attrs.as_deref(), + &qargs1, + &cargs1, + &op2.instruction.operation.view(), + &op2.instruction.params, + op2.instruction.extra_attrs.as_deref(), + &qargs2, + &cargs2, + max_num_qubits, + ) + } + + #[pyo3(signature=(op1, qargs1, cargs1, op2, qargs2, cargs2, max_num_qubits=3))] + #[allow(clippy::too_many_arguments)] + fn commute( + &mut self, + py: Python, + op1: OperationFromPython, + qargs1: Option<&Bound>, + cargs1: Option<&Bound>, + op2: OperationFromPython, + qargs2: Option<&Bound>, + cargs2: Option<&Bound>, + max_num_qubits: u32, + ) -> PyResult { + let qargs1 = + qargs1.map_or_else(|| Ok(PyTuple::empty_bound(py)), PySequenceMethods::to_tuple)?; + let cargs1 = + cargs1.map_or_else(|| Ok(PyTuple::empty_bound(py)), PySequenceMethods::to_tuple)?; + let qargs2 = + qargs2.map_or_else(|| Ok(PyTuple::empty_bound(py)), PySequenceMethods::to_tuple)?; + let cargs2 = + cargs2.map_or_else(|| Ok(PyTuple::empty_bound(py)), PySequenceMethods::to_tuple)?; + + let (qargs1, qargs2) = get_bits::(py, &qargs1, &qargs2)?; + let (cargs1, cargs2) = get_bits::(py, &cargs1, &cargs2)?; + + self.commute_inner( + py, + &op1.operation.view(), + &op1.params, + op1.extra_attrs.as_deref(), + &qargs1, + &cargs1, + &op2.operation.view(), + &op2.params, + op2.extra_attrs.as_deref(), + &qargs2, + &cargs2, + max_num_qubits, + ) + } + + /// Return the current number of cache entries + fn num_cached_entries(&self) -> usize { + self.current_cache_entries + } + + /// Clear the cache + fn clear_cached_commutations(&mut self) { + self.clear_cache() + } + + fn __getstate__(&self, py: Python) -> PyResult> { + let out_dict = PyDict::new_bound(py); + out_dict.set_item("cache_max_entries", self.cache_max_entries)?; + out_dict.set_item("current_cache_entries", self.current_cache_entries)?; + let cache_dict = PyDict::new_bound(py); + for (key, value) in &self.cache { + cache_dict.set_item(key, commutation_entry_to_pydict(py, value)?)?; + } + out_dict.set_item("cache", cache_dict)?; + out_dict.set_item("library", self.library.library.to_object(py))?; + out_dict.set_item("gates", self.gates.clone())?; + Ok(out_dict.unbind()) + } + + fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { + let dict_state = state.downcast_bound::(py)?; + self.cache_max_entries = dict_state + .get_item("cache_max_entries")? + .unwrap() + .extract()?; + self.current_cache_entries = dict_state + .get_item("current_cache_entries")? + .unwrap() + .extract()?; + self.library = CommutationLibrary { + library: dict_state.get_item("library")?.unwrap().extract()?, + }; + let raw_cache: Bound = dict_state.get_item("cache")?.unwrap().extract()?; + self.cache = HashMap::with_capacity(raw_cache.len()); + for (key, value) in raw_cache.iter() { + let value_dict: &Bound = value.downcast()?; + self.cache.insert( + key.extract()?, + commutation_cache_entry_from_pydict(value_dict)?, + ); + } + self.gates = dict_state.get_item("gates")?.unwrap().extract()?; + Ok(()) + } +} + +impl CommutationChecker { + #[allow(clippy::too_many_arguments)] + fn commute_inner( + &mut self, + py: Python, + op1: &OperationRef, + params1: &[Param], + attrs1: Option<&ExtraInstructionAttributes>, + qargs1: &[Qubit], + cargs1: &[Clbit], + op2: &OperationRef, + params2: &[Param], + attrs2: Option<&ExtraInstructionAttributes>, + qargs2: &[Qubit], + cargs2: &[Clbit], + max_num_qubits: u32, + ) -> PyResult { + if let Some(gates) = &self.gates { + if !gates.is_empty() && (!gates.contains(op1.name()) || !gates.contains(op2.name())) { + return Ok(false); + } + } + + let commutation: Option = commutation_precheck( + op1, + params1, + attrs1, + qargs1, + cargs1, + op2, + params2, + attrs2, + qargs2, + cargs2, + max_num_qubits, + ); + if let Some(is_commuting) = commutation { + return Ok(is_commuting); + } + + let reversed = if op1.num_qubits() != op2.num_qubits() { + op1.num_qubits() > op2.num_qubits() + } else { + (op1.name().len(), op1.name()) >= (op2.name().len(), op2.name()) + }; + let (first_params, second_params) = if reversed { + (params2, params1) + } else { + (params1, params2) + }; + let (first_op, second_op) = if reversed { (op2, op1) } else { (op1, op2) }; + let (first_qargs, second_qargs) = if reversed { + (qargs2, qargs1) + } else { + (qargs1, qargs2) + }; + + let skip_cache: bool = NO_CACHE_NAMES.contains(&first_op.name()) || + NO_CACHE_NAMES.contains(&second_op.name()) || + // Skip params that do not evaluate to floats for caching and commutation library + first_params.iter().any(|p| !matches!(p, Param::Float(_))) || + second_params.iter().any(|p| !matches!(p, Param::Float(_))); + + if skip_cache { + return self.commute_matmul( + py, + first_op, + first_params, + first_qargs, + second_op, + second_params, + second_qargs, + ); + } + + // Query commutation library + let relative_placement = get_relative_placement(first_qargs, second_qargs); + if let Some(is_commuting) = + self.library + .check_commutation_entries(first_op, second_op, &relative_placement) + { + return Ok(is_commuting); + } + + // Query cache + let key1 = hashable_params(first_params)?; + let key2 = hashable_params(second_params)?; + if let Some(commutation_dict) = self + .cache + .get(&(first_op.name().to_string(), second_op.name().to_string())) + { + let hashes = (key1.clone(), key2.clone()); + if let Some(commutation) = commutation_dict.get(&(relative_placement.clone(), hashes)) { + return Ok(*commutation); + } + } + + // Perform matrix multiplication to determine commutation + let is_commuting = self.commute_matmul( + py, + first_op, + first_params, + first_qargs, + second_op, + second_params, + second_qargs, + )?; + + // TODO: implement a LRU cache for this + if self.current_cache_entries >= self.cache_max_entries { + self.clear_cache(); + } + // Cache results from is_commuting + self.cache + .entry((first_op.name().to_string(), second_op.name().to_string())) + .and_modify(|entries| { + let key = (relative_placement.clone(), (key1.clone(), key2.clone())); + entries.insert(key, is_commuting); + self.current_cache_entries += 1; + }) + .or_insert_with(|| { + let mut entries = HashMap::with_capacity(1); + let key = (relative_placement, (key1, key2)); + entries.insert(key, is_commuting); + self.current_cache_entries += 1; + entries + }); + Ok(is_commuting) + } + + #[allow(clippy::too_many_arguments)] + fn commute_matmul( + &self, + py: Python, + first_op: &OperationRef, + first_params: &[Param], + first_qargs: &[Qubit], + second_op: &OperationRef, + second_params: &[Param], + second_qargs: &[Qubit], + ) -> PyResult { + // Compute relative positioning of qargs of the second gate to the first gate. + // Since the qargs come out the same BitData, we already know there are no accidential + // bit-duplications, but this code additionally maps first_qargs to [0..n] and then + // computes second_qargs relative to that. For example, it performs the mappings + // (first_qargs, second_qargs) = ( [1, 2], [0, 2] ) --> ( [0, 1], [2, 1] ) + // (first_qargs, second_qargs) = ( [1, 2, 0], [0, 3, 4] ) --> ( [0, 1, 2], [2, 3, 4] ) + // This re-shuffling is done to compute the correct kronecker product later. + let mut qarg: HashMap<&Qubit, Qubit> = HashMap::from_iter( + first_qargs + .iter() + .enumerate() + .map(|(i, q)| (q, Qubit(i as u32))), + ); + let mut num_qubits = first_qargs.len() as u32; + for q in second_qargs { + if !qarg.contains_key(q) { + qarg.insert(q, Qubit(num_qubits)); + num_qubits += 1; + } + } + + let first_qarg: Vec = Vec::from_iter((0..first_qargs.len() as u32).map(Qubit)); + let second_qarg: Vec = second_qargs.iter().map(|q| qarg[q]).collect(); + + if first_qarg.len() > second_qarg.len() { + return Err(QiskitError::new_err( + "first instructions must have at most as many qubits as the second instruction", + )); + }; + let first_mat = match get_matrix(py, first_op, first_params)? { + Some(matrix) => matrix, + None => return Ok(false), + }; + + let second_mat = match get_matrix(py, second_op, second_params)? { + Some(matrix) => matrix, + None => return Ok(false), + }; + + let rtol = 1e-5; + let atol = 1e-8; + if first_qarg == second_qarg { + match first_qarg.len() { + 1 => Ok(unitary_compose::commute_1q( + &first_mat.view(), + &second_mat.view(), + rtol, + atol, + )), + 2 => Ok(unitary_compose::commute_2q( + &first_mat.view(), + &second_mat.view(), + &[Qubit(0), Qubit(1)], + rtol, + atol, + )), + _ => Ok(unitary_compose::allclose( + &second_mat.dot(&first_mat).view(), + &first_mat.dot(&second_mat).view(), + rtol, + atol, + )), + } + } else { + // TODO Optimize this bit to avoid unnecessary Kronecker products: + // 1. We currently sort the operations for the cache by operation size, putting the + // *smaller* operation first: (smaller op, larger op) + // 2. This code here expands the first op to match the second -- hence we always + // match the operator sizes. + // This whole extension logic could be avoided since we know the second one is larger. + let extra_qarg2 = num_qubits - first_qarg.len() as u32; + let first_mat = if extra_qarg2 > 0 { + let id_op = Array2::::eye(usize::pow(2, extra_qarg2)); + kron(&id_op, &first_mat) + } else { + first_mat + }; + + // the 1 qubit case cannot happen, since that would already have been captured + // by the previous if clause; first_qarg == second_qarg (if they overlap they must + // be the same) + if num_qubits == 2 { + return Ok(unitary_compose::commute_2q( + &first_mat.view(), + &second_mat.view(), + &second_qarg, + rtol, + atol, + )); + }; + + let op12 = match unitary_compose::compose( + &first_mat.view(), + &second_mat.view(), + &second_qarg, + false, + ) { + Ok(matrix) => matrix, + Err(e) => return Err(PyRuntimeError::new_err(e)), + }; + let op21 = match unitary_compose::compose( + &first_mat.view(), + &second_mat.view(), + &second_qarg, + true, + ) { + Ok(matrix) => matrix, + Err(e) => return Err(PyRuntimeError::new_err(e)), + }; + Ok(unitary_compose::allclose( + &op12.view(), + &op21.view(), + rtol, + atol, + )) + } + } + + fn clear_cache(&mut self) { + self.cache.clear(); + self.current_cache_entries = 0; + } +} + +#[allow(clippy::too_many_arguments)] +fn commutation_precheck( + op1: &OperationRef, + params1: &[Param], + attrs1: Option<&ExtraInstructionAttributes>, + qargs1: &[Qubit], + cargs1: &[Clbit], + op2: &OperationRef, + params2: &[Param], + attrs2: Option<&ExtraInstructionAttributes>, + qargs2: &[Qubit], + cargs2: &[Clbit], + max_num_qubits: u32, +) -> Option { + if op1.control_flow() + || op2.control_flow() + || attrs1.is_some_and(|attr| attr.condition.is_some()) + || attrs2.is_some_and(|attr| attr.condition.is_some()) + { + return Some(false); + } + + // assuming the number of involved qubits to be small, this might be faster than set operations + if !qargs1.iter().any(|e| qargs2.contains(e)) && !cargs1.iter().any(|e| cargs2.contains(e)) { + return Some(true); + } + + if qargs1.len() > max_num_qubits as usize || qargs2.len() > max_num_qubits as usize { + return Some(false); + } + + if SUPPORTED_OP.contains(op1.name()) && SUPPORTED_OP.contains(op2.name()) { + return None; + } + + if is_commutation_skipped(op1, params1) || is_commutation_skipped(op2, params2) { + return Some(false); + } + + None +} + +fn get_matrix( + py: Python, + operation: &OperationRef, + params: &[Param], +) -> PyResult>> { + match operation.matrix(params) { + Some(matrix) => Ok(Some(matrix)), + None => match operation { + PyGateType(gate) => Ok(Some(matrix_via_operator(py, &gate.gate)?)), + PyOperationType(op) => Ok(Some(matrix_via_operator(py, &op.operation)?)), + _ => Ok(None), + }, + } +} + +fn matrix_via_operator(py: Python, py_obj: &PyObject) -> PyResult> { + Ok(QI_OPERATOR + .get_bound(py) + .call1((py_obj,))? + .getattr(intern!(py, "data"))? + .extract::>()? + .as_array() + .to_owned()) +} + +fn is_commutation_skipped(op: &T, params: &[Param]) -> bool +where + T: Operation, +{ + op.directive() + || SKIPPED_NAMES.contains(&op.name()) + || params + .iter() + .any(|x| matches!(x, Param::ParameterExpression(_))) +} + +fn get_relative_placement( + first_qargs: &[Qubit], + second_qargs: &[Qubit], +) -> SmallVec<[Option; 2]> { + let mut qubits_g2: HashMap<&Qubit, Qubit> = HashMap::with_capacity(second_qargs.len()); + second_qargs.iter().enumerate().for_each(|(i_g1, q_g1)| { + qubits_g2.insert_unique_unchecked(q_g1, Qubit(i_g1 as u32)); + }); + + first_qargs + .iter() + .map(|q_g0| qubits_g2.get(q_g0).copied()) + .collect() +} + +#[derive(Clone, Debug)] +#[pyclass] +pub struct CommutationLibrary { + pub library: Option>, +} + +impl CommutationLibrary { + fn check_commutation_entries( + &self, + first_op: &OperationRef, + second_op: &OperationRef, + relative_placement: &SmallVec<[Option; 2]>, + ) -> Option { + if let Some(library) = &self.library { + match library.get(&(first_op.name().to_string(), second_op.name().to_string())) { + Some(CommutationLibraryEntry::Commutes(b)) => Some(*b), + Some(CommutationLibraryEntry::QubitMapping(qm)) => { + qm.get(relative_placement).copied() + } + _ => None, + } + } else { + None + } + } +} + +#[pymethods] +impl CommutationLibrary { + #[new] + fn new(py_any: Option>) -> Self { + match py_any { + Some(pyob) => CommutationLibrary { + library: pyob + .extract::>() + .ok(), + }, + None => CommutationLibrary { + library: Some(HashMap::new()), + }, + } + } +} + +#[derive(Clone, Debug)] +pub enum CommutationLibraryEntry { + Commutes(bool), + QubitMapping(HashMap; 2]>, bool>), +} + +impl<'py> FromPyObject<'py> for CommutationLibraryEntry { + fn extract_bound(b: &Bound<'py, PyAny>) -> Result { + if let Ok(b) = b.extract::() { + return Ok(CommutationLibraryEntry::Commutes(b)); + } + let dict = b.downcast::()?; + let mut ret = hashbrown::HashMap::with_capacity(dict.len()); + for (k, v) in dict { + let raw_key: SmallVec<[Option; 2]> = k.extract()?; + let v: bool = v.extract()?; + let key = raw_key.into_iter().map(|key| key.map(Qubit)).collect(); + ret.insert(key, v); + } + Ok(CommutationLibraryEntry::QubitMapping(ret)) + } +} + +impl ToPyObject for CommutationLibraryEntry { + fn to_object(&self, py: Python) -> PyObject { + match self { + CommutationLibraryEntry::Commutes(b) => b.into_py(py), + CommutationLibraryEntry::QubitMapping(qm) => qm + .iter() + .map(|(k, v)| { + ( + PyTuple::new_bound(py, k.iter().map(|q| q.map(|t| t.0))), + PyBool::new_bound(py, *v), + ) + }) + .into_py_dict_bound(py) + .unbind() + .into(), + } + } +} + +type CacheKey = ( + SmallVec<[Option; 2]>, + (SmallVec<[ParameterKey; 3]>, SmallVec<[ParameterKey; 3]>), +); + +type CommutationCacheEntry = HashMap; + +fn commutation_entry_to_pydict(py: Python, entry: &CommutationCacheEntry) -> PyResult> { + let out_dict = PyDict::new_bound(py); + for (k, v) in entry.iter() { + let qubits = PyTuple::new_bound(py, k.0.iter().map(|q| q.map(|t| t.0))); + let params0 = PyTuple::new_bound(py, k.1 .0.iter().map(|pk| pk.0)); + let params1 = PyTuple::new_bound(py, k.1 .1.iter().map(|pk| pk.0)); + out_dict.set_item( + PyTuple::new_bound(py, [qubits, PyTuple::new_bound(py, [params0, params1])]), + PyBool::new_bound(py, *v), + )?; + } + Ok(out_dict.unbind()) +} + +fn commutation_cache_entry_from_pydict(dict: &Bound) -> PyResult { + let mut ret = hashbrown::HashMap::with_capacity(dict.len()); + for (k, v) in dict { + let raw_key: CacheKeyRaw = k.extract()?; + let qubits = raw_key.0.iter().map(|q| q.map(Qubit)).collect(); + let params0: SmallVec<_> = raw_key.1 .0; + let params1: SmallVec<_> = raw_key.1 .1; + let v: bool = v.extract()?; + ret.insert((qubits, (params0, params1)), v); + } + Ok(ret) +} + +type CacheKeyRaw = ( + SmallVec<[Option; 2]>, + (SmallVec<[ParameterKey; 3]>, SmallVec<[ParameterKey; 3]>), +); + +/// This newtype wraps a f64 to make it hashable so we can cache parameterized gates +/// based on the parameter value (assuming it's a float angle). However, Rust doesn't do +/// this by default and there are edge cases to track around it's usage. The biggest one +/// is this does not work with f64::NAN, f64::INFINITY, or f64::NEG_INFINITY +/// If you try to use these values with this type they will not work as expected. +/// This should only be used with the cache hashmap's keys and not used beyond that. +#[derive(Debug, Copy, Clone, PartialEq, FromPyObject)] +struct ParameterKey(f64); + +impl ParameterKey { + fn key(&self) -> u64 { + // If we get a -0 the to_bits() return is not equivalent to 0 + // because -0 has the sign bit set we'd be hashing 9223372036854775808 + // and be storing it separately from 0. So this normalizes all 0s to + // be represented by 0 + if self.0 == 0. { + 0 + } else { + self.0.to_bits() + } + } +} + +impl std::hash::Hash for ParameterKey { + fn hash(&self, state: &mut H) + where + H: std::hash::Hasher, + { + self.key().hash(state) + } +} + +impl Eq for ParameterKey {} + +fn hashable_params(params: &[Param]) -> PyResult> { + params + .iter() + .map(|x| { + if let Param::Float(x) = x { + // NaN and Infinity (negative or positive) are not valid + // parameter values and our hacks to store parameters in + // the cache HashMap don't take these into account. So return + // an error to Python if we encounter these values. + if x.is_nan() || x.is_infinite() { + Err(PyRuntimeError::new_err( + "Can't hash parameters that are infinite or NaN", + )) + } else { + Ok(ParameterKey(*x)) + } + } else { + Err(QiskitError::new_err( + "Unable to hash a non-float instruction parameter.", + )) + } + }) + .collect() +} + +#[pymodule] +pub fn commutation_checker(m: &Bound) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + Ok(()) +} diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 5414183d22cc..3a8c4bf51071 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -15,6 +15,7 @@ use std::env; use pyo3::import_exception; pub mod circuit_library; +pub mod commutation_checker; pub mod convert_2q_block_matrix; pub mod dense_layout; pub mod edge_collections; @@ -40,6 +41,7 @@ pub mod vf2_layout; mod rayon_ext; #[cfg(test)] mod test; +mod unitary_compose; #[inline] pub fn getenv_use_multiple_threads() -> bool { diff --git a/crates/accelerate/src/unitary_compose.rs b/crates/accelerate/src/unitary_compose.rs new file mode 100644 index 000000000000..b40f6c3eb564 --- /dev/null +++ b/crates/accelerate/src/unitary_compose.rs @@ -0,0 +1,240 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use ndarray::{Array, Array2, ArrayView, ArrayView2, IxDyn}; +use ndarray_einsum_beta::*; +use num_complex::{Complex, Complex64, ComplexFloat}; +use num_traits::Zero; +use qiskit_circuit::Qubit; + +static LOWERCASE: [u8; 26] = [ + b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', + b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', +]; + +static _UPPERCASE: [u8; 26] = [ + b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', + b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', +]; + +// Compose the operators given by `gate_unitary` and `overall_unitary`, i.e. apply one to the other +// as specified by the involved qubits given in `qubits` and the `front` parameter +pub fn compose( + gate_unitary: &ArrayView2, + overall_unitary: &ArrayView2, + qubits: &[Qubit], + front: bool, +) -> Result, &'static str> { + let gate_qubits = gate_unitary.shape()[0].ilog2() as usize; + + // Full composition of operators + if qubits.is_empty() { + if front { + return Ok(gate_unitary.dot(overall_unitary)); + } else { + return Ok(overall_unitary.dot(gate_unitary)); + } + } + // Compose with other on subsystem + let num_indices = gate_qubits; + let shift = if front { gate_qubits } else { 0usize }; + let right_mul = front; + + //Reshape current matrix + //Note that we must reverse the subsystem dimension order as + //qubit 0 corresponds to the right-most position in the tensor + //product, which is the last tensor wire index. + let tensor = per_qubit_shaped(gate_unitary); + let mat = per_qubit_shaped(overall_unitary); + let indices = qubits + .iter() + .map(|q| num_indices - 1 - q.0 as usize) + .collect::>(); + let num_rows = usize::pow(2, num_indices as u32); + + let res = _einsum_matmul(&tensor, &mat, &indices, shift, right_mul)? + .as_standard_layout() + .into_shape((num_rows, num_rows)) + .unwrap() + .into_dimensionality::() + .unwrap() + .to_owned(); + Ok(res) +} + +// Reshape an input matrix to (2, 2, ..., 2) depending on its dimensionality +fn per_qubit_shaped<'a>(array: &ArrayView2<'a, Complex>) -> ArrayView<'a, Complex64, IxDyn> { + let overall_shape = (0..array.shape()[0].ilog2() as usize) + .flat_map(|_| [2, 2]) + .collect::>(); + array.into_shape(overall_shape).unwrap() +} + +// Determine einsum strings for perform a matrix multiplication on the input matrices +fn _einsum_matmul( + tensor: &ArrayView, + mat: &ArrayView, + indices: &[usize], + shift: usize, + right_mul: bool, +) -> Result, &'static str> { + let rank = tensor.ndim(); + let rank_mat = mat.ndim(); + if rank_mat % 2 != 0 { + return Err("Contracted matrix must have an even number of indices."); + } + // Get einsum indices for tensor + let mut indices_tensor = (0..rank).collect::>(); + for (j, index) in indices.iter().enumerate() { + indices_tensor[index + shift] = rank + j; + } + // Get einsum indices for mat + let mat_contract = (rank..rank + indices.len()).rev().collect::>(); + let mat_free = indices + .iter() + .rev() + .map(|index| index + shift) + .collect::>(); + let indices_mat = if right_mul { + [mat_contract, mat_free].concat() + } else { + [mat_free, mat_contract].concat() + }; + + let tensor_einsum = unsafe { + String::from_utf8_unchecked(indices_tensor.iter().map(|c| LOWERCASE[*c]).collect()) + }; + let mat_einsum = + unsafe { String::from_utf8_unchecked(indices_mat.iter().map(|c| LOWERCASE[*c]).collect()) }; + + einsum( + format!("{},{}", tensor_einsum, mat_einsum).as_str(), + &[tensor, mat], + ) +} + +fn _einsum_matmul_helper(qubits: &[u32], num_qubits: usize) -> [String; 4] { + let tens_in: Vec = LOWERCASE[..num_qubits].to_vec(); + let mut tens_out: Vec = tens_in.clone(); + let mut mat_l: Vec = Vec::with_capacity(num_qubits); + let mut mat_r: Vec = Vec::with_capacity(num_qubits); + qubits.iter().rev().enumerate().for_each(|(pos, idx)| { + mat_r.push(tens_in[num_qubits - 1 - pos]); + mat_l.push(LOWERCASE[25 - pos]); + tens_out[num_qubits - 1 - *idx as usize] = LOWERCASE[25 - pos]; + }); + unsafe { + [ + String::from_utf8_unchecked(mat_l), + String::from_utf8_unchecked(mat_r), + String::from_utf8_unchecked(tens_in), + String::from_utf8_unchecked(tens_out), + ] + } +} + +fn _einsum_matmul_index(qubits: &[u32], num_qubits: usize) -> String { + assert!(num_qubits > 26, "Can't compute unitary of > 26 qubits"); + + let tens_r = unsafe { String::from_utf8_unchecked(_UPPERCASE[..num_qubits].to_vec()) }; + let [mat_l, mat_r, tens_lin, tens_lout] = _einsum_matmul_helper(qubits, num_qubits); + format!( + "{}{}, {}{}->{}{}", + mat_l, mat_r, tens_lin, tens_r, tens_lout, tens_r + ) +} + +pub fn commute_1q( + left: &ArrayView2, + right: &ArrayView2, + rtol: f64, + atol: f64, +) -> bool { + // This could allow for explicit hardcoded formulas, using less FLOPS, if we only + // consider an absolute tolerance. But for backward compatibility we now implement the full + // formula including relative tolerance handling. + for i in 0..2usize { + for j in 0..2usize { + let mut ab = Complex64::zero(); + let mut ba = Complex64::zero(); + for k in 0..2usize { + ab += left[[i, k]] * right[[k, j]]; + ba += right[[i, k]] * left[[k, j]]; + } + let sum = ab - ba; + if sum.abs() > atol + ba.abs() * rtol { + return false; + } + } + } + true +} + +pub fn commute_2q( + left: &ArrayView2, + right: &ArrayView2, + qargs: &[Qubit], + rtol: f64, + atol: f64, +) -> bool { + let rev = qargs[0].0 == 1; + for i in 0..4usize { + for j in 0..4usize { + // We compute AB and BA separately, to enable checking the relative difference + // (AB - BA)_ij > atol + rtol * BA_ij. This is due to backward compatibility and could + // maybe be changed in the future to save one complex number allocation. + let mut ab = Complex64::zero(); + let mut ba = Complex64::zero(); + for k in 0..4usize { + ab += left[[_ind(i, rev), _ind(k, rev)]] * right[[k, j]]; + ba += right[[i, k]] * left[[_ind(k, rev), _ind(j, rev)]]; + } + let sum = ab - ba; + if sum.abs() > atol + ba.abs() * rtol { + return false; + } + } + } + true +} + +#[inline] +fn _ind(i: usize, reversed: bool) -> usize { + if reversed { + // reverse the first two bits + ((i & 1) << 1) + ((i & 2) >> 1) + } else { + i + } +} + +/// For equally sized matrices, ``left`` and ``right``, check whether all entries are close +/// by the criterion +/// +/// |left_ij - right_ij| <= atol + rtol * right_ij +/// +/// This is analogous to NumPy's ``allclose`` function. +pub fn allclose( + left: &ArrayView2, + right: &ArrayView2, + rtol: f64, + atol: f64, +) -> bool { + for i in 0..left.nrows() { + for j in 0..left.ncols() { + if (left[(i, j)] - right[(i, j)]).abs() > atol + rtol * right[(i, j)].abs() { + return false; + } + } + } + true +} diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index e8971bc87629..24a4badf6539 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -13,14 +13,15 @@ use pyo3::prelude::*; use qiskit_accelerate::{ - circuit_library::circuit_library, convert_2q_block_matrix::convert_2q_block_matrix, - dense_layout::dense_layout, error_map::error_map, - euler_one_qubit_decomposer::euler_one_qubit_decomposer, isometry::isometry, nlayout::nlayout, - optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, results::results, - sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, - star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, - target_transpiler::target, two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, - utils::utils, vf2_layout::vf2_layout, + circuit_library::circuit_library, commutation_checker::commutation_checker, + convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, + error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, + isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, + pauli_exp_val::pauli_expval, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, + sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, + stochastic_swap::stochastic_swap, synthesis::synthesis, target_transpiler::target, + two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, utils::utils, + vf2_layout::vf2_layout, }; #[inline(always)] @@ -60,5 +61,6 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, uc_gate, "uc_gate")?; add_submodule(m, utils, "utils")?; add_submodule(m, vf2_layout, "vf2_layout")?; + add_submodule(m, commutation_checker, "commutation_checker")?; Ok(()) } diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 33933fd8fd7e..67384b38971a 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -86,6 +86,7 @@ sys.modules["qiskit._accelerate.synthesis.permutation"] = _accelerate.synthesis.permutation sys.modules["qiskit._accelerate.synthesis.linear"] = _accelerate.synthesis.linear sys.modules["qiskit._accelerate.synthesis.clifford"] = _accelerate.synthesis.clifford +sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase from qiskit.exceptions import QiskitError, MissingOptionalLibraryError diff --git a/qiskit/circuit/commutation_checker.py b/qiskit/circuit/commutation_checker.py index e070fe9b9b6f..2d474c7bac4e 100644 --- a/qiskit/circuit/commutation_checker.py +++ b/qiskit/circuit/commutation_checker.py @@ -12,47 +12,10 @@ """Code from commutative_analysis pass that checks commutation relations between DAG nodes.""" -from functools import lru_cache from typing import List, Union, Set, Optional -import numpy as np -from qiskit import QiskitError -from qiskit.circuit import Qubit from qiskit.circuit.operation import Operation -from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES -from qiskit.quantum_info.operators import Operator - -_skipped_op_names = {"measure", "reset", "delay", "initialize"} -_no_cache_op_names = {"annotated"} - -_supported_ops = { - "h", - "x", - "y", - "z", - "sx", - "sxdg", - "t", - "tdg", - "s", - "sdg", - "cx", - "cy", - "cz", - "swap", - "iswap", - "ecr", - "ccx", - "cswap", -} - - -@lru_cache(maxsize=None) -def _identity_op(num_qubits): - """Cached identity matrix""" - return Operator( - np.eye(2**num_qubits), input_dims=(2,) * num_qubits, output_dims=(2,) * num_qubits - ) +from qiskit._accelerate.commutation_checker import CommutationChecker as RustChecker class CommutationChecker: @@ -70,20 +33,7 @@ def __init__( *, gates: Optional[Set[str]] = None, ): - super().__init__() - if standard_gate_commutations is None: - self._standard_commutations = {} - else: - self._standard_commutations = standard_gate_commutations - self._cache_max_entries = cache_max_entries - - # self._cached_commutation has the same structure as standard_gate_commutations, i.e. a - # dict[pair of gate names][relative placement][tuple of gate parameters] := True/False - self._cached_commutations = {} - self._current_cache_entries = 0 - self._cache_miss = 0 - self._cache_hit = 0 - self._gate_names = gates + self.cc = RustChecker(standard_gate_commutations, cache_max_entries, gates) def commute_nodes( self, @@ -92,15 +42,7 @@ def commute_nodes( max_num_qubits: int = 3, ) -> bool: """Checks if two DAGOpNodes commute.""" - qargs1 = op1.qargs - cargs1 = op2.cargs - if not op1.is_standard_gate(): - op1 = op1.op - qargs2 = op2.qargs - cargs2 = op2.cargs - if not op2.is_standard_gate(): - op2 = op2.op - return self.commute(op1, qargs1, cargs1, op2, qargs2, cargs2, max_num_qubits) + return self.cc.commute_nodes(op1, op2, max_num_qubits) def commute( self, @@ -131,71 +73,15 @@ def commute( Returns: bool: whether two operations commute. """ - # Skip gates that are not specified. - if self._gate_names is not None: - if op1.name not in self._gate_names or op2.name not in self._gate_names: - return False - - structural_commutation = _commutation_precheck( - op1, qargs1, cargs1, op2, qargs2, cargs2, max_num_qubits - ) - - if structural_commutation is not None: - return structural_commutation - - first_op_tuple, second_op_tuple = _order_operations( - op1, qargs1, cargs1, op2, qargs2, cargs2 - ) - first_op, first_qargs, _ = first_op_tuple - second_op, second_qargs, _ = second_op_tuple - - skip_cache = first_op.name in _no_cache_op_names or second_op.name in _no_cache_op_names - - if skip_cache: - return _commute_matmul(first_op, first_qargs, second_op, second_qargs) - - commutation_lookup = self.check_commutation_entries( - first_op, first_qargs, second_op, second_qargs - ) - - if commutation_lookup is not None: - return commutation_lookup - - # Compute commutation via matrix multiplication - is_commuting = _commute_matmul(first_op, first_qargs, second_op, second_qargs) - - # Store result in this session's commutation_library - # TODO implement LRU cache or similar - # Rebuild cache if current cache exceeded max size - if self._current_cache_entries >= self._cache_max_entries: - self.clear_cached_commutations() - - first_params = getattr(first_op, "params", []) - second_params = getattr(second_op, "params", []) - if len(first_params) > 0 or len(second_params) > 0: - self._cached_commutations.setdefault((first_op.name, second_op.name), {}).setdefault( - _get_relative_placement(first_qargs, second_qargs), {} - )[ - (_hashable_parameters(first_params), _hashable_parameters(second_params)) - ] = is_commuting - else: - self._cached_commutations.setdefault((first_op.name, second_op.name), {})[ - _get_relative_placement(first_qargs, second_qargs) - ] = is_commuting - self._current_cache_entries += 1 - - return is_commuting + return self.cc.commute(op1, qargs1, cargs1, op2, qargs2, cargs2, max_num_qubits) def num_cached_entries(self): """Returns number of cached entries""" - return self._current_cache_entries + return self.cc.num_cached_entries() def clear_cached_commutations(self): """Clears the dictionary holding cached commutations""" - self._current_cache_entries = 0 - self._cache_miss = 0 - self._cache_hit = 0 - self._cached_commutations = {} + self.cc.clear_cached_commutations() def check_commutation_entries( self, @@ -215,272 +101,6 @@ def check_commutation_entries( Return: bool: True if the gates commute and false if it is not the case. """ - - # We don't precompute commutations for parameterized gates, yet - commutation = _query_commutation( - first_op, - first_qargs, - second_op, - second_qargs, - self._standard_commutations, - ) - - if commutation is not None: - return commutation - - commutation = _query_commutation( - first_op, - first_qargs, - second_op, - second_qargs, - self._cached_commutations, - ) - if commutation is None: - self._cache_miss += 1 - else: - self._cache_hit += 1 - return commutation - - -def _hashable_parameters(params): - """Convert the parameters of a gate into a hashable format for lookup in a dictionary. - - This aims to be fast in common cases, and is not intended to work outside of the lifetime of a - single commutation pass; it does not handle mutable state correctly if the state is actually - changed.""" - try: - hash(params) - return params - except TypeError: - pass - if isinstance(params, (list, tuple)): - return tuple(_hashable_parameters(x) for x in params) - if isinstance(params, np.ndarray): - # Using the bytes of the matrix as key is runtime efficient but requires more space: 128 bits - # times the number of parameters instead of a single 64 bit id. However, by using the bytes as - # an id, we can reuse the cached commutations between different passes. - return (np.ndarray, params.tobytes()) - # Catch anything else with a slow conversion. - return ("fallback", str(params)) - - -def is_commutation_supported(op, qargs, max_num_qubits): - """ - Filter operations whose commutation is not supported due to bugs in transpiler passes invoking - commutation analysis. - Args: - op (Operation): operation to be checked for commutation relation. - qargs (list[Qubit]): qubits the operation acts on. - max_num_qubits (int): The maximum number of qubits to check commutativity for. - - Return: - True if determining the commutation of op is currently supported - """ - # If the number of qubits is beyond what we check, stop here and do not even check in the - # pre-defined supported operations - if len(qargs) > max_num_qubits: - return False - - # Check if the operation is pre-approved, otherwise go through the checks - if op.name in _supported_ops: - return True - - # Commutation of ControlFlow gates also not supported yet. This may be pending a control flow graph. - if op.name in CONTROL_FLOW_OP_NAMES: - return False - - if getattr(op, "_directive", False) or op.name in _skipped_op_names: - return False - - if getattr(op, "is_parameterized", False) and op.is_parameterized(): - return False - - return True - - -def _commutation_precheck( - op1: Operation, - qargs1: List, - cargs1: List, - op2: Operation, - qargs2: List, - cargs2: List, - max_num_qubits, -): - # Bug in CommutativeCancellation, e.g. see gh-8553 - if getattr(op1, "condition", False) or getattr(op2, "condition", False): - return False - - if set(qargs1).isdisjoint(qargs2) and set(cargs1).isdisjoint(cargs2): - return True - - if not is_commutation_supported(op1, qargs1, max_num_qubits) or not is_commutation_supported( - op2, qargs2, max_num_qubits - ): - return False - - return None - - -def _get_relative_placement(first_qargs: List[Qubit], second_qargs: List[Qubit]) -> tuple: - """Determines the relative qubit placement of two gates. Note: this is NOT symmetric. - - Args: - first_qargs (DAGOpNode): first gate - second_qargs (DAGOpNode): second gate - - Return: - A tuple that describes the relative qubit placement: E.g. - _get_relative_placement(CX(0, 1), CX(1, 2)) would return (None, 0) as there is no overlap on - the first qubit of the first gate but there is an overlap on the second qubit of the first gate, - i.e. qubit 0 of the second gate. Likewise, - _get_relative_placement(CX(1, 2), CX(0, 1)) would return (1, None) - """ - qubits_g2 = {q_g1: i_g1 for i_g1, q_g1 in enumerate(second_qargs)} - return tuple(qubits_g2.get(q_g0, None) for q_g0 in first_qargs) - - -@lru_cache(maxsize=10**3) -def _persistent_id(op_name: str) -> int: - """Returns an integer id of a string that is persistent over different python executions (note that - hash() can not be used, i.e. its value can change over two python executions) - Args: - op_name (str): The string whose integer id should be determined. - Return: - The integer id of the input string. - """ - return int.from_bytes(bytes(op_name, encoding="utf-8"), byteorder="big", signed=True) - - -def _order_operations( - op1: Operation, qargs1: List, cargs1: List, op2: Operation, qargs2: List, cargs2: List -): - """Orders two operations in a canonical way that is persistent over - @different python versions and executions - Args: - op1: first operation. - qargs1: first operation's qubits. - cargs1: first operation's clbits. - op2: second operation. - qargs2: second operation's qubits. - cargs2: second operation's clbits. - Return: - The input operations in a persistent, canonical order. - """ - op1_tuple = (op1, qargs1, cargs1) - op2_tuple = (op2, qargs2, cargs2) - least_qubits_op, most_qubits_op = ( - (op1_tuple, op2_tuple) if op1.num_qubits < op2.num_qubits else (op2_tuple, op1_tuple) - ) - # prefer operation with the least number of qubits as first key as this results in shorter keys - if op1.num_qubits != op2.num_qubits: - return least_qubits_op, most_qubits_op - else: - return ( - (op1_tuple, op2_tuple) - if _persistent_id(op1.name) < _persistent_id(op2.name) - else (op2_tuple, op1_tuple) - ) - - -def _query_commutation( - first_op: Operation, - first_qargs: List, - second_op: Operation, - second_qargs: List, - _commutation_lib: dict, -) -> Union[bool, None]: - """Queries and returns the commutation of a pair of operations from a provided commutation library - Args: - first_op: first operation. - first_qargs: first operation's qubits. - first_cargs: first operation's clbits. - second_op: second operation. - second_qargs: second operation's qubits. - second_cargs: second operation's clbits. - _commutation_lib (dict): dictionary of commutation relations - Return: - True if first_op and second_op commute, False if they do not commute and - None if the commutation is not in the library - """ - - commutation = _commutation_lib.get((first_op.name, second_op.name), None) - - # Return here if the commutation is constant over all relative placements of the operations - if commutation is None or isinstance(commutation, bool): - return commutation - - # If we arrive here, there is an entry in the commutation library but it depends on the - # placement of the operations and also possibly on operation parameters - if isinstance(commutation, dict): - commutation_after_placement = commutation.get( - _get_relative_placement(first_qargs, second_qargs), None - ) - # if we have another dict in commutation_after_placement, commutation depends on params - if isinstance(commutation_after_placement, dict): - # Param commutation entry exists and must be a dict - first_params = getattr(first_op, "params", []) - second_params = getattr(second_op, "params", []) - return commutation_after_placement.get( - ( - _hashable_parameters(first_params), - _hashable_parameters(second_params), - ), - None, - ) - else: - # queried commutation is True, False or None - return commutation_after_placement - else: - raise ValueError("Expected commutation to be None, bool or a dict") - - -def _commute_matmul( - first_ops: Operation, first_qargs: List, second_op: Operation, second_qargs: List -): - qarg = {q: i for i, q in enumerate(first_qargs)} - num_qubits = len(qarg) - for q in second_qargs: - if q not in qarg: - qarg[q] = num_qubits - num_qubits += 1 - - first_qarg = tuple(qarg[q] for q in first_qargs) - second_qarg = tuple(qarg[q] for q in second_qargs) - - from qiskit.dagcircuit.dagnode import DAGOpNode - - # If we have a DAGOpNode here we've received a StandardGate definition from - # rust and we can manually pull the matrix to use for the Operators - if isinstance(first_ops, DAGOpNode): - first_ops = first_ops.matrix - if isinstance(second_op, DAGOpNode): - second_op = second_op.matrix - - # try to generate an Operator out of op, if this succeeds we can determine commutativity, otherwise - # return false - try: - operator_1 = Operator( - first_ops, input_dims=(2,) * len(first_qarg), output_dims=(2,) * len(first_qarg) - ) - operator_2 = Operator( - second_op, input_dims=(2,) * len(second_qarg), output_dims=(2,) * len(second_qarg) + return self.cc.library.check_commutation_entries( + first_op, first_qargs, second_op, second_qargs ) - except QiskitError: - return False - - if first_qarg == second_qarg: - # Use full composition if possible to get the fastest matmul paths. - op12 = operator_1.compose(operator_2) - op21 = operator_2.compose(operator_1) - else: - # Expand operator_1 to be large enough to contain operator_2 as well; this relies on qargs1 - # being the lowest possible indices so the identity can be tensored before it. - extra_qarg2 = num_qubits - len(first_qarg) - if extra_qarg2: - id_op = _identity_op(extra_qarg2) - operator_1 = id_op.tensor(operator_1) - op12 = operator_1.compose(operator_2, qargs=second_qarg, front=False) - op21 = operator_1.compose(operator_2, qargs=second_qarg, front=True) - ret = op12 == op21 - return ret diff --git a/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py index 5f9744fc860a..97324e2376cd 100644 --- a/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py @@ -12,6 +12,7 @@ """Cancel pairs of inverse gates exploiting commutation relations.""" from qiskit.circuit.commutation_library import SessionCommutationChecker as scc + from qiskit.dagcircuit import DAGCircuit, DAGOpNode from qiskit.quantum_info import Operator from qiskit.quantum_info.operators.predicates import matrix_equal @@ -34,6 +35,7 @@ def __init__(self, matrix_based: bool = False, max_qubits: int = 4): """ self._matrix_based = matrix_based self._max_qubits = max_qubits + self.comm_checker = scc super().__init__() def _skip_node(self, node): @@ -92,7 +94,6 @@ def run(self, dag: DAGCircuit): removed = [False for _ in range(circ_size)] - cc = scc phase_update = 0 for idx1 in range(0, circ_size): @@ -118,13 +119,9 @@ def run(self, dag: DAGCircuit): matched_idx2 = idx2 break - if not cc.commute( - topo_sorted_nodes[idx1].op, - topo_sorted_nodes[idx1].qargs, - topo_sorted_nodes[idx1].cargs, - topo_sorted_nodes[idx2].op, - topo_sorted_nodes[idx2].qargs, - topo_sorted_nodes[idx2].cargs, + if not self.comm_checker.commute_nodes( + topo_sorted_nodes[idx1], + topo_sorted_nodes[idx2], max_num_qubits=self._max_qubits, ): break diff --git a/releasenotes/notes/rust-commutation-checker-c738e67efa9d292f.yaml b/releasenotes/notes/rust-commutation-checker-c738e67efa9d292f.yaml new file mode 100644 index 000000000000..bcfcbe18caf0 --- /dev/null +++ b/releasenotes/notes/rust-commutation-checker-c738e67efa9d292f.yaml @@ -0,0 +1,6 @@ +--- +features_transpiler: + - | + The the :class:`.CommutationChecker` class has been reimplemented in + Rust. This retains the same functionality as before but is now + significantly in most cases. diff --git a/test/python/circuit/test_commutation_checker.py b/test/python/circuit/test_commutation_checker.py index 677b191cb0cb..a0aeae5ca2c3 100644 --- a/test/python/circuit/test_commutation_checker.py +++ b/test/python/circuit/test_commutation_checker.py @@ -24,9 +24,10 @@ AnnotatedOperation, InverseModifier, ControlModifier, + Gate, ) from qiskit.circuit.commutation_library import SessionCommutationChecker as scc - +from qiskit.dagcircuit import DAGOpNode from qiskit.circuit.library import ( ZGate, XGate, @@ -44,6 +45,16 @@ from test import QiskitTestCase # pylint: disable=wrong-import-order +class NewGateCX(Gate): + """A dummy class containing an cx gate unknown to the commutation checker's library.""" + + def __init__(self): + super().__init__("new_cx", 2, []) + + def to_matrix(self): + return np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex) + + class TestCommutationChecker(QiskitTestCase): """Test CommutationChecker class.""" @@ -51,206 +62,105 @@ def test_simple_gates(self): """Check simple commutation relations between gates, experimenting with different orders of gates, different orders of qubits, different sets of qubits over which gates are defined, and so on.""" - # should commute - res = scc.commute(ZGate(), [0], [], CXGate(), [0, 1], []) - self.assertTrue(res) + # should commute + self.assertTrue(scc.commute(ZGate(), [0], [], CXGate(), [0, 1], [])) # should not commute - res = scc.commute(ZGate(), [1], [], CXGate(), [0, 1], []) - self.assertFalse(res) - + self.assertFalse(scc.commute(ZGate(), [1], [], CXGate(), [0, 1], [])) # should not commute - res = scc.commute(XGate(), [0], [], CXGate(), [0, 1], []) - self.assertFalse(res) - + self.assertFalse(scc.commute(XGate(), [0], [], CXGate(), [0, 1], [])) # should commute - res = scc.commute(XGate(), [1], [], CXGate(), [0, 1], []) - self.assertTrue(res) - + self.assertTrue(scc.commute(XGate(), [1], [], CXGate(), [0, 1], [])) # should not commute - res = scc.commute(XGate(), [1], [], CXGate(), [1, 0], []) - self.assertFalse(res) - + self.assertFalse(scc.commute(XGate(), [1], [], CXGate(), [1, 0], [])) # should commute - res = scc.commute(XGate(), [0], [], CXGate(), [1, 0], []) - self.assertTrue(res) - + self.assertTrue(scc.commute(XGate(), [0], [], CXGate(), [1, 0], [])) # should commute - res = scc.commute(CXGate(), [1, 0], [], XGate(), [0], []) - self.assertTrue(res) - + self.assertTrue(scc.commute(CXGate(), [1, 0], [], XGate(), [0], [])) # should not commute - res = scc.commute(CXGate(), [1, 0], [], XGate(), [1], []) - self.assertFalse(res) - + self.assertFalse(scc.commute(CXGate(), [1, 0], [], XGate(), [1], [])) # should commute - res = scc.commute( - CXGate(), - [1, 0], - [], - CXGate(), - [1, 0], - [], - ) - self.assertTrue(res) - + self.assertTrue(scc.commute(CXGate(), [1, 0], [], CXGate(), [1, 0], [])) # should not commute - res = scc.commute( - CXGate(), - [1, 0], - [], - CXGate(), - [0, 1], - [], - ) - self.assertFalse(res) - + self.assertFalse(scc.commute(CXGate(), [1, 0], [], CXGate(), [0, 1], [])) # should commute - res = scc.commute( - CXGate(), - [1, 0], - [], - CXGate(), - [1, 2], - [], - ) - self.assertTrue(res) - + self.assertTrue(scc.commute(CXGate(), [1, 0], [], CXGate(), [1, 2], [])) # should not commute - res = scc.commute( - CXGate(), - [1, 0], - [], - CXGate(), - [2, 1], - [], - ) - self.assertFalse(res) - + self.assertFalse(scc.commute(CXGate(), [1, 0], [], CXGate(), [2, 1], [])) # should commute - res = scc.commute( - CXGate(), - [1, 0], - [], - CXGate(), - [2, 3], - [], - ) - self.assertTrue(res) - - res = scc.commute(XGate(), [2], [], CCXGate(), [0, 1, 2], []) - self.assertTrue(res) - - res = scc.commute(CCXGate(), [0, 1, 2], [], CCXGate(), [0, 2, 1], []) - self.assertFalse(res) + self.assertTrue(scc.commute(CXGate(), [1, 0], [], CXGate(), [2, 3], [])) + self.assertTrue(scc.commute(XGate(), [2], [], CCXGate(), [0, 1, 2], [])) + self.assertFalse(scc.commute(CCXGate(), [0, 1, 2], [], CCXGate(), [0, 2, 1], [])) def test_passing_quantum_registers(self): """Check that passing QuantumRegisters works correctly.""" qr = QuantumRegister(4) - # should commute - res = scc.commute(CXGate(), [qr[1], qr[0]], [], CXGate(), [qr[1], qr[2]], []) - self.assertTrue(res) - + self.assertTrue(scc.commute(CXGate(), [qr[1], qr[0]], [], CXGate(), [qr[1], qr[2]], [])) # should not commute - res = scc.commute(CXGate(), [qr[0], qr[1]], [], CXGate(), [qr[1], qr[2]], []) - self.assertFalse(res) + self.assertFalse(scc.commute(CXGate(), [qr[0], qr[1]], [], CXGate(), [qr[1], qr[2]], [])) def test_standard_gates_commutations(self): """Check that commutativity checker uses standard gates commutations as expected.""" scc.clear_cached_commutations() - scc.clear_cached_commutations() - res = scc.commute(ZGate(), [0], [], CXGate(), [0, 1], []) - self.assertTrue(res) + self.assertTrue(scc.commute(ZGate(), [0], [], CXGate(), [0, 1], [])) self.assertEqual(scc.num_cached_entries(), 0) def test_caching_positive_results(self): """Check that hashing positive results in commutativity checker works as expected.""" scc.clear_cached_commutations() - NewGateCX = type("MyClass", (CXGate,), {"content": {}}) - NewGateCX.name = "cx_new" - - res = scc.commute(ZGate(), [0], [], NewGateCX(), [0, 1], []) - self.assertTrue(res) - self.assertGreater(len(scc._cached_commutations), 0) + self.assertTrue(scc.commute(ZGate(), [0], [], NewGateCX(), [0, 1], [])) + self.assertGreater(scc.num_cached_entries(), 0) def test_caching_lookup_with_non_overlapping_qubits(self): """Check that commutation lookup with non-overlapping qubits works as expected.""" scc.clear_cached_commutations() - res = scc.commute(CXGate(), [0, 2], [], CXGate(), [0, 1], []) - self.assertTrue(res) - res = scc.commute(CXGate(), [0, 1], [], CXGate(), [1, 2], []) - self.assertFalse(res) - self.assertEqual(len(scc._cached_commutations), 0) + self.assertTrue(scc.commute(CXGate(), [0, 2], [], CXGate(), [0, 1], [])) + self.assertFalse(scc.commute(CXGate(), [0, 1], [], CXGate(), [1, 2], [])) + self.assertEqual(scc.num_cached_entries(), 0) def test_caching_store_and_lookup_with_non_overlapping_qubits(self): """Check that commutations storing and lookup with non-overlapping qubits works as expected.""" - cc_lenm = scc.num_cached_entries() - NewGateCX = type("MyClass", (CXGate,), {"content": {}}) - NewGateCX.name = "cx_new" - res = scc.commute(NewGateCX(), [0, 2], [], CXGate(), [0, 1], []) - self.assertTrue(res) - res = scc.commute(NewGateCX(), [0, 1], [], CXGate(), [1, 2], []) - self.assertFalse(res) - res = scc.commute(NewGateCX(), [1, 4], [], CXGate(), [1, 6], []) - self.assertTrue(res) - res = scc.commute(NewGateCX(), [5, 3], [], CXGate(), [3, 1], []) - self.assertFalse(res) - self.assertEqual(scc.num_cached_entries(), cc_lenm + 2) + scc_lenm = scc.num_cached_entries() + self.assertTrue(scc.commute(NewGateCX(), [0, 2], [], CXGate(), [0, 1], [])) + self.assertFalse(scc.commute(NewGateCX(), [0, 1], [], CXGate(), [1, 2], [])) + self.assertTrue(scc.commute(NewGateCX(), [1, 4], [], CXGate(), [1, 6], [])) + self.assertFalse(scc.commute(NewGateCX(), [5, 3], [], CXGate(), [3, 1], [])) + self.assertEqual(scc.num_cached_entries(), scc_lenm + 2) def test_caching_negative_results(self): """Check that hashing negative results in commutativity checker works as expected.""" scc.clear_cached_commutations() - NewGateCX = type("MyClass", (CXGate,), {"content": {}}) - NewGateCX.name = "cx_new" - - res = scc.commute(XGate(), [0], [], NewGateCX(), [0, 1], []) - self.assertFalse(res) - self.assertGreater(len(scc._cached_commutations), 0) + self.assertFalse(scc.commute(XGate(), [0], [], NewGateCX(), [0, 1], [])) + self.assertGreater(scc.num_cached_entries(), 0) def test_caching_different_qubit_sets(self): """Check that hashing same commutativity results over different qubit sets works as expected.""" scc.clear_cached_commutations() - NewGateCX = type("MyClass", (CXGate,), {"content": {}}) - NewGateCX.name = "cx_new" # All the following should be cached in the same way # though each relation gets cached twice: (A, B) and (B, A) scc.commute(XGate(), [0], [], NewGateCX(), [0, 1], []) scc.commute(XGate(), [10], [], NewGateCX(), [10, 20], []) scc.commute(XGate(), [10], [], NewGateCX(), [10, 5], []) scc.commute(XGate(), [5], [], NewGateCX(), [5, 7], []) - self.assertEqual(len(scc._cached_commutations), 1) - self.assertEqual(scc._cache_miss, 1) - self.assertEqual(scc._cache_hit, 3) + self.assertEqual(scc.num_cached_entries(), 1) def test_cache_with_param_gates(self): """Check commutativity between (non-parameterized) gates with parameters.""" scc.clear_cached_commutations() - res = scc.commute(RZGate(0), [0], [], XGate(), [0], []) - self.assertTrue(res) - - res = scc.commute(RZGate(np.pi / 2), [0], [], XGate(), [0], []) - self.assertFalse(res) - res = scc.commute(RZGate(np.pi / 2), [0], [], RZGate(0), [0], []) - self.assertTrue(res) + self.assertTrue(scc.commute(RZGate(0), [0], [], XGate(), [0], [])) + self.assertFalse(scc.commute(RZGate(np.pi / 2), [0], [], XGate(), [0], [])) + self.assertTrue(scc.commute(RZGate(np.pi / 2), [0], [], RZGate(0), [0], [])) - res = scc.commute(RZGate(np.pi / 2), [1], [], XGate(), [1], []) - self.assertFalse(res) + self.assertFalse(scc.commute(RZGate(np.pi / 2), [1], [], XGate(), [1], [])) self.assertEqual(scc.num_cached_entries(), 3) - self.assertEqual(scc._cache_miss, 3) - self.assertEqual(scc._cache_hit, 1) def test_gates_with_parameters(self): """Check commutativity between (non-parameterized) gates with parameters.""" - res = scc.commute(RZGate(0), [0], [], XGate(), [0], []) - self.assertTrue(res) - - res = scc.commute(RZGate(np.pi / 2), [0], [], XGate(), [0], []) - self.assertFalse(res) - - res = scc.commute(RZGate(np.pi / 2), [0], [], RZGate(0), [0], []) - self.assertTrue(res) + self.assertTrue(scc.commute(RZGate(0), [0], [], XGate(), [0], [])) + self.assertFalse(scc.commute(RZGate(np.pi / 2), [0], [], XGate(), [0], [])) + self.assertTrue(scc.commute(RZGate(np.pi / 2), [0], [], RZGate(0), [0], [])) def test_parameterized_gates(self): """Check commutativity between parameterized gates, both with free and with @@ -272,84 +182,68 @@ def test_parameterized_gates(self): self.assertFalse(cx_gate.is_parameterized()) # We should detect that these gates commute - res = scc.commute(rz_gate, [0], [], cx_gate, [0, 1], []) - self.assertTrue(res) + self.assertTrue(scc.commute(rz_gate, [0], [], cx_gate, [0, 1], [])) # We should detect that these gates commute - res = scc.commute(rz_gate, [0], [], rz_gate, [0], []) - self.assertTrue(res) + self.assertTrue(scc.commute(rz_gate, [0], [], rz_gate, [0], [])) # We should detect that parameterized gates over disjoint qubit subsets commute - res = scc.commute(rz_gate_theta, [0], [], rz_gate_theta, [1], []) - self.assertTrue(res) + self.assertTrue(scc.commute(rz_gate_theta, [0], [], rz_gate_theta, [1], [])) # We should detect that parameterized gates over disjoint qubit subsets commute - res = scc.commute(rz_gate_theta, [0], [], rz_gate_phi, [1], []) - self.assertTrue(res) + self.assertTrue(scc.commute(rz_gate_theta, [0], [], rz_gate_phi, [1], [])) # We should detect that parameterized gates over disjoint qubit subsets commute - res = scc.commute(rz_gate_theta, [2], [], cx_gate, [1, 3], []) - self.assertTrue(res) + self.assertTrue(scc.commute(rz_gate_theta, [2], [], cx_gate, [1, 3], [])) # However, for now commutativity checker should return False when checking # commutativity between a parameterized gate and some other gate, when # the two gates are over intersecting qubit subsets. # This check should be changed if commutativity checker is extended to # handle parameterized gates better. - res = scc.commute(rz_gate_theta, [0], [], cx_gate, [0, 1], []) - self.assertFalse(res) + self.assertFalse(scc.commute(rz_gate_theta, [0], [], cx_gate, [0, 1], [])) - res = scc.commute(rz_gate_theta, [0], [], rz_gate, [0], []) - self.assertFalse(res) + self.assertFalse(scc.commute(rz_gate_theta, [0], [], rz_gate, [0], [])) def test_measure(self): """Check commutativity involving measures.""" # Measure is over qubit 0, while gate is over a disjoint subset of qubits # We should be able to swap these. - res = scc.commute(Measure(), [0], [0], CXGate(), [1, 2], []) - self.assertTrue(res) + self.assertTrue(scc.commute(Measure(), [0], [0], CXGate(), [1, 2], [])) # Measure and gate have intersecting set of qubits # We should not be able to swap these. - res = scc.commute(Measure(), [0], [0], CXGate(), [0, 2], []) - self.assertFalse(res) + self.assertFalse(scc.commute(Measure(), [0], [0], CXGate(), [0, 2], [])) # Measures over different qubits and clbits - res = scc.commute(Measure(), [0], [0], Measure(), [1], [1]) - self.assertTrue(res) + self.assertTrue(scc.commute(Measure(), [0], [0], Measure(), [1], [1])) # Measures over different qubits but same classical bit # We should not be able to swap these. - res = scc.commute(Measure(), [0], [0], Measure(), [1], [0]) - self.assertFalse(res) + self.assertFalse(scc.commute(Measure(), [0], [0], Measure(), [1], [0])) # Measures over same qubits but different classical bit # ToDo: can we swap these? # Currently checker takes the safe approach and returns False. - res = scc.commute(Measure(), [0], [0], Measure(), [0], [1]) - self.assertFalse(res) + self.assertFalse(scc.commute(Measure(), [0], [0], Measure(), [0], [1])) def test_barrier(self): """Check commutativity involving barriers.""" # A gate should not commute with a barrier # (at least if these are over intersecting qubit sets). - res = scc.commute(Barrier(4), [0, 1, 2, 3], [], CXGate(), [1, 2], []) - self.assertFalse(res) + self.assertFalse(scc.commute(Barrier(4), [0, 1, 2, 3], [], CXGate(), [1, 2], [])) # Does it even make sense to have a barrier over a subset of qubits? # Though in this case, it probably makes sense to say that barrier and gate can be swapped. - res = scc.commute(Barrier(4), [0, 1, 2, 3], [], CXGate(), [5, 6], []) - self.assertTrue(res) + self.assertTrue(scc.commute(Barrier(4), [0, 1, 2, 3], [], CXGate(), [5, 6], [])) def test_reset(self): """Check commutativity involving resets.""" # A gate should not commute with reset when the qubits intersect. - res = scc.commute(Reset(), [0], [], CXGate(), [0, 2], []) - self.assertFalse(res) + self.assertFalse(scc.commute(Reset(), [0], [], CXGate(), [0, 2], [])) # A gate should commute with reset when the qubits are disjoint. - res = scc.commute(Reset(), [0], [], CXGate(), [1, 2], []) - self.assertTrue(res) + self.assertTrue(scc.commute(Reset(), [0], [], CXGate(), [1, 2], [])) def test_conditional_gates(self): """Check commutativity involving conditional gates.""" @@ -358,22 +252,26 @@ def test_conditional_gates(self): # Currently, in all cases commutativity checker should returns False. # This is definitely suboptimal. - res = scc.commute(CXGate().c_if(cr[0], 0), [qr[0], qr[1]], [], XGate(), [qr[2]], []) - self.assertFalse(res) - - res = scc.commute(CXGate().c_if(cr[0], 0), [qr[0], qr[1]], [], XGate(), [qr[1]], []) - self.assertFalse(res) - - res = scc.commute( - CXGate().c_if(cr[0], 0), [qr[0], qr[1]], [], CXGate().c_if(cr[0], 0), [qr[0], qr[1]], [] + self.assertFalse( + scc.commute(CXGate().c_if(cr[0], 0), [qr[0], qr[1]], [], XGate(), [qr[2]], []) ) - self.assertFalse(res) - - res = scc.commute(XGate().c_if(cr[0], 0), [qr[0]], [], XGate().c_if(cr[0], 1), [qr[0]], []) - self.assertFalse(res) - - res = scc.commute(XGate().c_if(cr[0], 0), [qr[0]], [], XGate(), [qr[0]], []) - self.assertFalse(res) + self.assertFalse( + scc.commute(CXGate().c_if(cr[0], 0), [qr[0], qr[1]], [], XGate(), [qr[1]], []) + ) + self.assertFalse( + scc.commute( + CXGate().c_if(cr[0], 0), + [qr[0], qr[1]], + [], + CXGate().c_if(cr[0], 0), + [qr[0], qr[1]], + [], + ) + ) + self.assertFalse( + scc.commute(XGate().c_if(cr[0], 0), [qr[0]], [], XGate().c_if(cr[0], 1), [qr[0]], []) + ) + self.assertFalse(scc.commute(XGate().c_if(cr[0], 0), [qr[0]], [], XGate(), [qr[0]], [])) def test_complex_gates(self): """Check commutativity involving more complex gates.""" @@ -382,16 +280,14 @@ def test_complex_gates(self): # lf1 is equivalent to swap(0, 1), and lf2 to swap(1, 2). # These do not commute. - res = scc.commute(lf1, [0, 1, 2], [], lf2, [0, 1, 2], []) - self.assertFalse(res) + self.assertFalse(scc.commute(lf1, [0, 1, 2], [], lf2, [0, 1, 2], [])) lf3 = LinearFunction([[0, 1, 0], [0, 0, 1], [1, 0, 0]]) lf4 = LinearFunction([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) # lf3 is permutation 1->2, 2->3, 3->1. # lf3 is the inverse permutation 1->3, 2->1, 3->2. # These commute. - res = scc.commute(lf3, [0, 1, 2], [], lf4, [0, 1, 2], []) - self.assertTrue(res) + self.assertTrue(scc.commute(lf3, [0, 1, 2], [], lf4, [0, 1, 2], [])) def test_equal_annotated_operations_commute(self): """Check commutativity involving the same annotated operation.""" @@ -435,17 +331,28 @@ def test_c7x_gate(self): def test_wide_gates_over_nondisjoint_qubits(self): """Test that checking wide gates does not lead to memory problems.""" - res = scc.commute(MCXGate(29), list(range(30)), [], XGate(), [0], []) - self.assertFalse(res) - res = scc.commute(XGate(), [0], [], MCXGate(29), list(range(30)), []) - self.assertFalse(res) + self.assertFalse(scc.commute(MCXGate(29), list(range(30)), [], XGate(), [0], [])) def test_wide_gates_over_disjoint_qubits(self): """Test that wide gates still commute when they are over disjoint sets of qubits.""" - res = scc.commute(MCXGate(29), list(range(30)), [], XGate(), [30], []) - self.assertTrue(res) - res = scc.commute(XGate(), [30], [], MCXGate(29), list(range(30)), []) - self.assertTrue(res) + self.assertTrue(scc.commute(MCXGate(29), list(range(30)), [], XGate(), [30], [])) + self.assertTrue(scc.commute(XGate(), [30], [], MCXGate(29), list(range(30)), [])) + + def test_serialization(self): + """Test that the commutation checker is correctly serialized""" + import pickle + + scc.clear_cached_commutations() + self.assertTrue(scc.commute(ZGate(), [0], [], NewGateCX(), [0, 1], [])) + cc2 = pickle.loads(pickle.dumps(scc)) + self.assertEqual(cc2.num_cached_entries(), 1) + dop1 = DAGOpNode(ZGate(), qargs=[0], cargs=[]) + dop2 = DAGOpNode(NewGateCX(), qargs=[0, 1], cargs=[]) + cc2.commute_nodes(dop1, dop2) + dop1 = DAGOpNode(ZGate(), qargs=[0], cargs=[]) + dop2 = DAGOpNode(CXGate(), qargs=[0, 1], cargs=[]) + cc2.commute_nodes(dop1, dop2) + self.assertEqual(cc2.num_cached_entries(), 1) if __name__ == "__main__": diff --git a/tools/build_standard_commutations.py b/tools/build_standard_commutations.py index 0e1fcdf1797d..31f1fe03822b 100644 --- a/tools/build_standard_commutations.py +++ b/tools/build_standard_commutations.py @@ -19,12 +19,70 @@ import itertools from functools import lru_cache from typing import List -from qiskit.circuit.commutation_checker import _get_relative_placement, _order_operations from qiskit.circuit import Gate, CommutationChecker import qiskit.circuit.library.standard_gates as stdg from qiskit.dagcircuit import DAGOpNode +@lru_cache(maxsize=10**3) +def _persistent_id(op_name: str) -> int: + """Returns an integer id of a string that is persistent over different python executions (note that + hash() can not be used, i.e. its value can change over two python executions) + Args: + op_name (str): The string whose integer id should be determined. + Return: + The integer id of the input string. + """ + return int.from_bytes(bytes(op_name, encoding="utf-8"), byteorder="big", signed=True) + + +def _order_operations(op1, qargs1, cargs1, op2, qargs2, cargs2): + """Orders two operations in a canonical way that is persistent over + @different python versions and executions + Args: + op1: first operation. + qargs1: first operation's qubits. + cargs1: first operation's clbits. + op2: second operation. + qargs2: second operation's qubits. + cargs2: second operation's clbits. + Return: + The input operations in a persistent, canonical order. + """ + op1_tuple = (op1, qargs1, cargs1) + op2_tuple = (op2, qargs2, cargs2) + least_qubits_op, most_qubits_op = ( + (op1_tuple, op2_tuple) if op1.num_qubits < op2.num_qubits else (op2_tuple, op1_tuple) + ) + # prefer operation with the least number of qubits as first key as this results in shorter keys + if op1.num_qubits != op2.num_qubits: + return least_qubits_op, most_qubits_op + else: + return ( + (op1_tuple, op2_tuple) + if _persistent_id(op1.name) < _persistent_id(op2.name) + else (op2_tuple, op1_tuple) + ) + + +def _get_relative_placement(first_qargs, second_qargs) -> tuple: + """Determines the relative qubit placement of two gates. Note: this is NOT symmetric. + + Args: + first_qargs (DAGOpNode): first gate + second_qargs (DAGOpNode): second gate + + Return: + A tuple that describes the relative qubit placement: E.g. + _get_relative_placement(CX(0, 1), CX(1, 2)) would return (None, 0) as there is no overlap on + the first qubit of the first gate but there is an overlap on the second qubit of the first gate, + i.e. qubit 0 of the second gate. Likewise, + _get_relative_placement(CX(1, 2), CX(0, 1)) would return (1, None) + """ + qubits_g2 = {q_g1: i_g1 for i_g1, q_g1 in enumerate(second_qargs)} + return tuple(qubits_g2.get(q_g0, None) for q_g0 in first_qargs) + + @lru_cache(None) def _get_unparameterizable_gates() -> List[Gate]: """Retrieve a list of non-parmaterized gates with up to 3 qubits, using the python inspection module From 8f3308475ce4d0fbce1a95e7397360a9b352b496 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 3 Sep 2024 14:46:34 +0100 Subject: [PATCH 42/85] Fix extraction of controlled parametric gates (#13067) The `mutable` check in the controlled-gate `OperationFromPython` extraction logic to check for a mutated `base_gate` was overzealous, and would return false positives for parametric controlled gates. The only modification to `base_gate` of a standard-library gate that would not have caused data-model problems from Python space would be setting the base-gate label, which is used for a public feature of the circuit visualisers. The change to `get_standard_gate_name_mapping` is just a minor convenience to make the gate objects directly appendable to a circuit; previously, each `Parameter` object was distinct and had a UUID clash with others of the same name, so could not be used together. The new behaviour is purely a convenience for tests; it largely should not be useful for users to directly append these gates. --- crates/circuit/src/circuit_instruction.rs | 12 +++- .../library/standard_gates/__init__.py | 57 +++++++++++-------- ...arametric-controlled-1a495f6f7ce89397.yaml | 8 +++ test/python/circuit/test_rust_equivalence.py | 17 ++++++ 4 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 releasenotes/notes/extract-standard-parametric-controlled-1a495f6f7ce89397.yaml diff --git a/crates/circuit/src/circuit_instruction.rs b/crates/circuit/src/circuit_instruction.rs index b0620d78fb75..215d337ab052 100644 --- a/crates/circuit/src/circuit_instruction.rs +++ b/crates/circuit/src/circuit_instruction.rs @@ -547,12 +547,18 @@ impl<'py> FromPyObject<'py> for OperationFromPython { // mapping to avoid an `isinstance` check on `ControlledGate` - a standard gate has // nonzero `num_ctrl_qubits` iff it is a `ControlledGate`. // - // `ControlledGate` also has a `base_gate` attribute, and we don't track enough in Rust - // space to handle the case that that was mutated away from a standard gate. + // `ControlledGate` also has a `base_gate` attribute related to its historical + // implementation, which technically allows mutations from Python space. The only + // mutation of a standard gate's `base_gate` that wouldn't have already broken the + // Python-space data model is setting a label, so we just catch that case and default + // back to non-standard-gate handling in that case. if standard.num_ctrl_qubits() != 0 && ((ob.getattr(intern!(py, "ctrl_state"))?.extract::()? != (1 << standard.num_ctrl_qubits()) - 1) - || ob.getattr(intern!(py, "mutable"))?.extract()?) + || !ob + .getattr(intern!(py, "base_gate"))? + .getattr(intern!(py, "label"))? + .is_none()) { break 'standard; } diff --git a/qiskit/circuit/library/standard_gates/__init__.py b/qiskit/circuit/library/standard_gates/__init__.py index a4741386343f..19a2bf770da2 100644 --- a/qiskit/circuit/library/standard_gates/__init__.py +++ b/qiskit/circuit/library/standard_gates/__init__.py @@ -54,6 +54,13 @@ def get_standard_gate_name_mapping(): from qiskit.circuit.delay import Delay from qiskit.circuit.reset import Reset + lambda_ = Parameter("λ") + theta = Parameter("ϴ") + phi = Parameter("φ") + gamma = Parameter("γ") + beta = Parameter("β") + time = Parameter("t") + # Standard gates library mapping, multicontrolled gates not included since they're # variable width gates = [ @@ -61,38 +68,37 @@ def get_standard_gate_name_mapping(): SXGate(), XGate(), CXGate(), - RZGate(Parameter("λ")), - RGate(Parameter("ϴ"), Parameter("φ")), - Reset(), + RZGate(lambda_), + RGate(theta, phi), C3SXGate(), CCXGate(), DCXGate(), CHGate(), - CPhaseGate(Parameter("ϴ")), - CRXGate(Parameter("ϴ")), - CRYGate(Parameter("ϴ")), - CRZGate(Parameter("ϴ")), + CPhaseGate(theta), + CRXGate(theta), + CRYGate(theta), + CRZGate(theta), CSwapGate(), CSXGate(), - CUGate(Parameter("ϴ"), Parameter("φ"), Parameter("λ"), Parameter("γ")), - CU1Gate(Parameter("λ")), - CU3Gate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")), + CUGate(theta, phi, lambda_, gamma), + CU1Gate(lambda_), + CU3Gate(theta, phi, lambda_), CYGate(), CZGate(), CCZGate(), - GlobalPhaseGate(Parameter("ϴ")), + GlobalPhaseGate(theta), HGate(), - PhaseGate(Parameter("ϴ")), + PhaseGate(theta), RCCXGate(), RC3XGate(), - RXGate(Parameter("ϴ")), - RXXGate(Parameter("ϴ")), - RYGate(Parameter("ϴ")), - RYYGate(Parameter("ϴ")), - RZZGate(Parameter("ϴ")), - RZXGate(Parameter("ϴ")), - XXMinusYYGate(Parameter("ϴ"), Parameter("β")), - XXPlusYYGate(Parameter("ϴ"), Parameter("β")), + RXGate(theta), + RXXGate(theta), + RYGate(theta), + RYYGate(theta), + RZZGate(theta), + RZXGate(theta), + XXMinusYYGate(theta, beta), + XXPlusYYGate(theta, beta), ECRGate(), SGate(), SdgGate(), @@ -103,13 +109,14 @@ def get_standard_gate_name_mapping(): SXdgGate(), TGate(), TdgGate(), - UGate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")), - U1Gate(Parameter("λ")), - U2Gate(Parameter("φ"), Parameter("λ")), - U3Gate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")), + UGate(theta, phi, lambda_), + U1Gate(lambda_), + U2Gate(phi, lambda_), + U3Gate(theta, phi, lambda_), YGate(), ZGate(), - Delay(Parameter("t")), + Delay(time), + Reset(), Measure(), ] name_mapping = {gate.name: gate for gate in gates} diff --git a/releasenotes/notes/extract-standard-parametric-controlled-1a495f6f7ce89397.yaml b/releasenotes/notes/extract-standard-parametric-controlled-1a495f6f7ce89397.yaml new file mode 100644 index 000000000000..ea4e69dd245f --- /dev/null +++ b/releasenotes/notes/extract-standard-parametric-controlled-1a495f6f7ce89397.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Parametric controlled standard-library gates (such as :class:`.CRXGate`) will now get correctly + extracted to a Rust-space standard gate when using :meth:`.QuantumCircuit.append` and the gate + object. Previously there was a discrepancy where using the :meth:`.QuantumCircuit.crx` method + would cause a correct extraction in Rust space, but the :meth:`~.QuantumCirucit.append` form + would not. The bug should generally not have caused any unsoundness from Python. diff --git a/test/python/circuit/test_rust_equivalence.py b/test/python/circuit/test_rust_equivalence.py index b6de438d04dd..b6ec28f82e8d 100644 --- a/test/python/circuit/test_rust_equivalence.py +++ b/test/python/circuit/test_rust_equivalence.py @@ -227,3 +227,20 @@ def test_non_default_controls(self): circuit.append(gate, [0, 1, 2]) self.assertIsNotNone(getattr(gate, "_standard_gate", None)) np.testing.assert_almost_equal(Operator(circuit.data[0].operation).to_matrix(), op) + + def test_extracted_as_standard_gate(self): + """Test that every gate in the standard library gets correctly extracted as a Rust-space + `StandardGate` in its default configuration when passed through `append`.""" + standards = set() + qc = QuantumCircuit(4) + for name, gate in get_standard_gate_name_mapping().items(): + if gate._standard_gate is None: + # Not a standard gate. + continue + standards.add(name) + qc.append(gate, qc.qubits[: gate.num_qubits], []) + # Sanity check: the test should have found at least one standard gate in the mapping. + self.assertNotEqual(standards, set()) + + extracted = {inst.name for inst in qc.data if inst.is_standard_gate()} + self.assertEqual(standards, extracted) From dde09f9d62140d898015601a82a50443cd132600 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 3 Sep 2024 09:46:48 -0400 Subject: [PATCH 43/85] Remove benchmarks for deprecated (or soon to be) features (#13064) This commit removes benchmarks for the deprecated assemble module and the soon to be (see #13063) deprecated pulse module. While these features are still supported it's not worth the spending the limited CPU time we hacve on the benchmarking system to track the performance of these components anymore. --- test/benchmarks/assembler.py | 51 -- test/benchmarks/pulse/__init__.py | 11 - test/benchmarks/pulse/load_pulse_defaults.py | 552 ------------------ .../benchmarks/pulse/schedule_construction.py | 174 ------ test/benchmarks/pulse/schedule_lowering.py | 85 --- 5 files changed, 873 deletions(-) delete mode 100644 test/benchmarks/assembler.py delete mode 100644 test/benchmarks/pulse/__init__.py delete mode 100644 test/benchmarks/pulse/load_pulse_defaults.py delete mode 100644 test/benchmarks/pulse/schedule_construction.py delete mode 100644 test/benchmarks/pulse/schedule_lowering.py diff --git a/test/benchmarks/assembler.py b/test/benchmarks/assembler.py deleted file mode 100644 index 03d349088c86..000000000000 --- a/test/benchmarks/assembler.py +++ /dev/null @@ -1,51 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2023 -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -# pylint: disable=no-member,invalid-name,missing-docstring,no-name-in-module -# pylint: disable=attribute-defined-outside-init,unsubscriptable-object - -from qiskit.compiler import assemble -from qiskit.assembler import disassemble - -from .utils import random_circuit - - -class AssemblerBenchmarks: - params = ([8], [4096], [1, 100]) - param_names = ["n_qubits", "depth", "number of circuits"] - timeout = 600 - version = 2 - - def setup(self, n_qubits, depth, number_of_circuits): - seed = 42 - self.circuit = random_circuit(n_qubits, depth, measure=True, conditional=True, seed=seed) - self.circuits = [self.circuit] * number_of_circuits - - def time_assemble_circuit(self, _, __, ___): - assemble(self.circuits) - - -class DisassemblerBenchmarks: - params = ([8], [4096], [1, 100]) - param_names = ["n_qubits", "depth", "number of circuits"] - timeout = 600 - - def setup(self, n_qubits, depth, number_of_circuits): - seed = 424242 - self.circuit = random_circuit(n_qubits, depth, measure=True, conditional=True, seed=seed) - self.circuits = [self.circuit] * number_of_circuits - self.qobj = assemble(self.circuits) - - def time_disassemble_circuit(self, _, __, ___): - # TODO: QObj is getting deprecated. Remove once that happens - # https://github.com/Qiskit/qiskit/pull/12649 - disassemble(self.qobj) diff --git a/test/benchmarks/pulse/__init__.py b/test/benchmarks/pulse/__init__.py deleted file mode 100644 index c7325a848299..000000000000 --- a/test/benchmarks/pulse/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2023 -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. diff --git a/test/benchmarks/pulse/load_pulse_defaults.py b/test/benchmarks/pulse/load_pulse_defaults.py deleted file mode 100644 index 770ac1563b2b..000000000000 --- a/test/benchmarks/pulse/load_pulse_defaults.py +++ /dev/null @@ -1,552 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2023 -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -# pylint: disable=missing-docstring,invalid-name,no-member -# pylint: disable=attribute-defined-outside-init - -import numpy as np - -from qiskit.providers.models.pulsedefaults import PulseDefaults -from qiskit.compiler import schedule -from qiskit.circuit import QuantumCircuit, Gate - - -def gen_source(num_random_gate): - - # minimum data to instantiate pulse defaults. - # cmd def contains cx, rz, sx, u3, measure - # and random gate (custom waveform of 100 dt + 2 fc) - - qobj_dict = { - "qubit_freq_est": [5.0, 5.1], - "meas_freq_est": [7.0, 7.0], - "buffer": 0, - "pulse_library": [], - "cmd_def": [ - { - "name": "cx", - "qubits": [0, 1], - "sequence": [ - { - "ch": "d0", - "name": "fc", - "phase": -3.141592653589793, - "t0": 0, - }, - { - "ch": "d0", - "label": "Y90p_d0", - "name": "parametric_pulse", - "parameters": { - "amp": (0.0022743565483134 + 0.14767107967944j), - "beta": 0.5218372954777448, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 0, - }, - { - "ch": "d0", - "label": "CR90p_d0_u1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.03583301328943 - 0.0006486874906466j), - "duration": 1104, - "sigma": 64, - "width": 848, - }, - "pulse_shape": "gaussian_square", - "t0": 96, - }, - { - "ch": "d0", - "label": "CR90m_d0_u1", - "name": "parametric_pulse", - "parameters": { - "amp": (-0.03583301328943 + 0.000648687490646j), - "duration": 1104, - "sigma": 64, - "width": 848, - }, - "pulse_shape": "gaussian_square", - "t0": 1296, - }, - { - "ch": "d0", - "name": "fc", - "phase": -1.5707963267948966, - "t0": 2400, - }, - { - "ch": "d0", - "label": "X90p_d0", - "name": "parametric_pulse", - "parameters": { - "amp": (0.14766707017470 - 0.002521280908868j), - "beta": 0.5218372954777448, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 2400, - }, - { - "ch": "d1", - "name": "fc", - "phase": -1.5707963267948966, - "t0": 0, - }, - { - "ch": "d1", - "label": "X90p_d1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.19074973504459 + 0.004525711677119j), - "beta": -1.2815198779814807, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 0, - }, - { - "ch": "d1", - "label": "Xp_d1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.3872223088586379 + 0j), - "beta": -1.498502772395478, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 1200, - }, - { - "ch": "d1", - "label": "Y90m_d1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.00285052543950 - 0.19078212177897j), - "beta": -1.2815198779814807, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 2400, - }, - { - "ch": "u0", - "name": "fc", - "phase": -1.5707963267948966, - "t0": 0, - }, - { - "ch": "u1", - "name": "fc", - "phase": -3.141592653589793, - "t0": 0, - }, - { - "ch": "u1", - "label": "CR90p_u1", - "name": "parametric_pulse", - "parameters": { - "amp": (-0.1629668182698 - 0.8902610676540j), - "duration": 1104, - "sigma": 64, - "width": 848, - }, - "pulse_shape": "gaussian_square", - "t0": 96, - }, - { - "ch": "u1", - "label": "CR90m_u1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.16296681826986 + 0.8902610676540j), - "duration": 1104, - "sigma": 64, - "width": 848, - }, - "pulse_shape": "gaussian_square", - "t0": 1296, - }, - { - "ch": "u1", - "name": "fc", - "phase": -1.5707963267948966, - "t0": 2400, - }, - ], - }, - { - "name": "rz", - "qubits": [0], - "sequence": [ - { - "ch": "d0", - "name": "fc", - "phase": "-(P0)", - "t0": 0, - }, - { - "ch": "u1", - "name": "fc", - "phase": "-(P0)", - "t0": 0, - }, - ], - }, - { - "name": "rz", - "qubits": [1], - "sequence": [ - { - "ch": "d1", - "name": "fc", - "phase": "-(P0)", - "t0": 0, - }, - { - "ch": "u0", - "name": "fc", - "phase": "-(P0)", - "t0": 0, - }, - ], - }, - { - "name": "sx", - "qubits": [0], - "sequence": [ - { - "ch": "d0", - "label": "X90p_d0", - "name": "parametric_pulse", - "parameters": { - "amp": (0.14766707017470 - 0.002521280908868j), - "beta": 0.5218372954777448, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 0, - } - ], - }, - { - "name": "sx", - "qubits": [1], - "sequence": [ - { - "ch": "d1", - "label": "X90p_d0", - "name": "parametric_pulse", - "parameters": { - "amp": (0.19074973504459 + 0.004525711677119j), - "beta": -1.2815198779814807, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 0, - } - ], - }, - { - "name": "u3", - "qubits": [0], - "sequence": [ - { - "ch": "d0", - "name": "fc", - "phase": "-(P2)", - "t0": 0, - }, - { - "ch": "d0", - "label": "X90p_d0", - "name": "parametric_pulse", - "parameters": { - "amp": (0.14766707017470 - 0.002521280908868j), - "beta": 0.5218372954777448, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 0, - }, - { - "ch": "d0", - "name": "fc", - "phase": "-(P0)", - "t0": 96, - }, - { - "ch": "d0", - "label": "X90m_d0", - "name": "parametric_pulse", - "parameters": { - "amp": (-0.14767107967944 + 0.002274356548313j), - "beta": 0.5218372954777448, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 96, - }, - { - "ch": "d0", - "name": "fc", - "phase": "-(P1)", - "t0": 192, - }, - { - "ch": "u1", - "name": "fc", - "phase": "-(P2)", - "t0": 0, - }, - { - "ch": "u1", - "name": "fc", - "phase": "-(P0)", - "t0": 96, - }, - { - "ch": "u1", - "name": "fc", - "phase": "-(P1)", - "t0": 192, - }, - ], - }, - { - "name": "u3", - "qubits": [1], - "sequence": [ - { - "ch": "d1", - "name": "fc", - "phase": "-(P2)", - "t0": 0, - }, - { - "ch": "d1", - "label": "X90p_d1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.19074973504459 + 0.004525711677119j), - "beta": -1.2815198779814807, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 0, - }, - { - "ch": "d1", - "name": "fc", - "phase": "-(P0)", - "t0": 96, - }, - { - "ch": "d1", - "label": "X90m_d1", - "name": "parametric_pulse", - "parameters": { - "amp": (-0.19078212177897 - 0.002850525439509j), - "beta": -1.2815198779814807, - "duration": 96, - "sigma": 24, - }, - "pulse_shape": "drag", - "t0": 96, - }, - { - "ch": "d1", - "name": "fc", - "phase": "-(P1)", - "t0": 192, - }, - { - "ch": "u0", - "name": "fc", - "phase": "-(P2)", - "t0": 0, - }, - { - "ch": "u0", - "name": "fc", - "phase": "-(P0)", - "t0": 96, - }, - { - "ch": "u0", - "name": "fc", - "phase": "-(P1)", - "t0": 192, - }, - ], - }, - { - "name": "measure", - "qubits": [0, 1], - "sequence": [ - { - "ch": "m0", - "label": "M_m0", - "name": "parametric_pulse", - "parameters": { - "amp": (-0.3003200790496 + 0.3069634566518j), - "duration": 1792, - "sigma": 64, - "width": 1536, - }, - "pulse_shape": "gaussian_square", - "t0": 0, - }, - { - "ch": "m1", - "label": "M_m1", - "name": "parametric_pulse", - "parameters": { - "amp": (0.26292757124962 + 0.14446138680205j), - "duration": 1792, - "sigma": 64, - "width": 1536, - }, - "pulse_shape": "gaussian_square", - "t0": 0, - }, - { - "ch": "m0", - "duration": 1504, - "name": "delay", - "t0": 1792, - }, - { - "ch": "m1", - "duration": 1504, - "name": "delay", - "t0": 1792, - }, - { - "duration": 1792, - "memory_slot": [0, 1], - "name": "acquire", - "qubits": [0, 1], - "t0": 0, - }, - ], - }, - ], - } - - # add random waveform gate entries to increase overhead - for i in range(num_random_gate): - for qind in (0, 1): - samples = np.random.random(100) - - gate_name = f"ramdom_gate_{i}" - sample_name = f"random_sample_q{qind}_{i}" - - qobj_dict["pulse_library"].append( - { - "name": sample_name, - "samples": samples, - } - ) - qobj_dict["cmd_def"].append( - { - "name": gate_name, - "qubits": [qind], - "sequence": [ - { - "ch": f"d{qind}", - "name": "fc", - "phase": "-(P0)", - "t0": 0, - }, - { - "ch": f"d{qind}", - "label": gate_name, - "name": sample_name, - "t0": 0, - }, - { - "ch": f"d{qind}", - "name": "fc", - "phase": "(P0)", - "t0": 100, - }, - ], - }, - ) - - return qobj_dict - - -class PulseDefaultsBench: - - params = ([0, 10, 100, 1000],) - param_names = [ - "number of random gates", - ] - - def setup(self, num_random_gate): - self.source = gen_source(num_random_gate) - - def time_building_defaults(self, _): - PulseDefaults.from_dict(self.source) - - -class CircuitSchedulingBench: - - params = ([1, 2, 3, 15],) - param_names = [ - "number of unit cell repetition", - ] - - def setup(self, repeat_unit_cell): - source = gen_source(1) - defaults = PulseDefaults.from_dict(source) - - self.inst_map = defaults.instruction_schedule_map - self.meas_map = [[0, 1]] - self.dt = 0.222e-9 - - rng = np.random.default_rng(123) - - qc = QuantumCircuit(2) - for _ in range(repeat_unit_cell): - randdom_gate = Gate("ramdom_gate_0", 1, list(rng.random(1))) - qc.cx(0, 1) - qc.append(randdom_gate, [0]) - qc.sx(0) - qc.rz(1.57, 0) - qc.append(randdom_gate, [1]) - qc.sx(1) - qc.rz(1.57, 1) - qc.measure_all() - self.qc = qc - - def time_scheduling_circuits(self, _): - schedule( - self.qc, - inst_map=self.inst_map, - meas_map=self.meas_map, - dt=self.dt, - ) diff --git a/test/benchmarks/pulse/schedule_construction.py b/test/benchmarks/pulse/schedule_construction.py deleted file mode 100644 index 13b889a19513..000000000000 --- a/test/benchmarks/pulse/schedule_construction.py +++ /dev/null @@ -1,174 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2023 -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -# pylint: disable=missing-docstring,invalid-name,no-member -# pylint: disable=attribute-defined-outside-init - -import numpy as np - -from qiskit.circuit import Parameter, QuantumCircuit, Gate -from qiskit.pulse import builder, library, channels - - -class EchoedCrossResonanceConstructionBench: - def setup(self): - - with builder.build() as x_ctrl: - builder.play( - library.Drag(160, 0.2, 40, 1.5), - channels.DriveChannel(0), - ) - self.x_ctrl = x_ctrl - - with builder.build() as cr45p: - builder.play( - library.GaussianSquare(800, 0.4, 64, 544), - channels.ControlChannel(0), - ) - builder.play( - library.GaussianSquare(800, 0.1, 64, 544), - channels.DriveChannel(1), - ) - self.cr45p = cr45p - - def time_full_scratch(self): - # Full scratch in a single builder context - with builder.build(): - with builder.align_sequential(): - with builder.align_left(): - builder.play( - library.GaussianSquare(800, 0.4, 64, 544), - channels.ControlChannel(0), - ) - builder.play( - library.GaussianSquare(800, 0.1, 64, 544), - channels.DriveChannel(1), - ) - builder.play( - library.Drag(160, 0.2, 40, 1.5), - channels.DriveChannel(0), - ) - with builder.phase_offset( - np.pi, - channels.ControlChannel(0), - channels.DriveChannel(1), - ): - with builder.align_left(): - builder.play( - library.GaussianSquare(800, 0.4, 64, 544), - channels.ControlChannel(0), - ) - builder.play( - library.GaussianSquare(800, 0.1, 64, 544), - channels.DriveChannel(1), - ) - builder.play( - library.Drag(160, 0.2, 40, 1.5), - channels.DriveChannel(0), - ) - - def time_with_call(self): - # Call subroutine, internally creates reference and assign immediately - with builder.build(): - with builder.align_sequential(): - builder.call(self.cr45p) - builder.call(self.x_ctrl) - with builder.phase_offset( - np.pi, - channels.ControlChannel(0), - channels.DriveChannel(1), - ): - builder.call(self.cr45p) - builder.call(self.x_ctrl) - - def time_assign_later(self): - # Create placeholder and assign subroutine at a later time - with builder.build() as temp_sched: - with builder.align_sequential(): - builder.reference("cr45p", "q0", "q1") - builder.reference("x", "q0") - with builder.phase_offset( - np.pi, - channels.ControlChannel(0), - channels.DriveChannel(1), - ): - builder.reference("cr45p", "q0", "q1") - builder.reference("x", "q0") - - temp_sched.assign_references( - { - ("cr45p", "q0", "q1"): self.cr45p, - ("x", "q0"): self.x_ctrl, - }, - inplace=True, - ) - - -class ParameterizedScheduleBench: - - params = [3, 11, 31, 51] - - def setup(self, nscan): - self.p0 = Parameter("P0") - self.p1 = Parameter("P1") - self.p2 = Parameter("P2") - - with builder.build() as schedule: - builder.play( - library.Constant(self.p0, self.p1), - channels.DriveChannel(self.p2), - ) - self.schedule = schedule - - with builder.build() as outer_schedule: - builder.reference("subroutine") - outer_schedule.assign_references({("subroutine",): schedule}, inplace=True) - self.outer_schedule = outer_schedule - - gate = Gate("my_gate", 1, [self.p0, self.p1, self.p2]) - qc = QuantumCircuit(1) - qc.append(gate, [0]) - qc.add_calibration(gate, (0,), schedule) - self.qc = qc - - # list of parameters - self.amps = np.linspace(-1, 1, nscan) - - def time_assign_single_schedule(self, _): - - out = [] - for amp in self.amps: - assigned = self.schedule.assign_parameters( - {self.p0: 100, self.p1: amp, self.p2: 0}, - inplace=False, - ) - out.append(assigned) - - def time_assign_parameterized_subroutine(self, _): - - out = [] - for amp in self.amps: - assigned = self.outer_schedule.assign_parameters( - {self.p0: 100, self.p1: amp, self.p2: 0}, - inplace=False, - ) - out.append(assigned) - - def time_assign_through_pulse_gate(self, _): - - out = [] - for amp in self.amps: - assigned = self.qc.assign_parameters( - {self.p0: 100, self.p1: amp, self.p2: 0}, - inplace=False, - ) - out.append(assigned) diff --git a/test/benchmarks/pulse/schedule_lowering.py b/test/benchmarks/pulse/schedule_lowering.py deleted file mode 100644 index 38b09a8411be..000000000000 --- a/test/benchmarks/pulse/schedule_lowering.py +++ /dev/null @@ -1,85 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2023 -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -# pylint: disable=missing-docstring,invalid-name,no-member -# pylint: disable=attribute-defined-outside-init - -import numpy as np - -from qiskit.pulse import builder, library, channels -from qiskit.pulse.transforms import target_qobj_transform - - -def build_complicated_schedule(): - - with builder.build() as schedule: - with builder.align_sequential(): - with builder.align_right(): - with builder.phase_offset(np.pi, channels.ControlChannel(2)): - with builder.align_sequential(): - for _ in range(5): - builder.play( - library.GaussianSquare(640, 0.1, 64, 384), - channels.ControlChannel(2), - ) - builder.play( - library.Constant(1920, 0.1), - channels.DriveChannel(1), - ) - builder.barrier( - channels.DriveChannel(0), - channels.DriveChannel(1), - channels.DriveChannel(2), - ) - builder.delay(800, channels.DriveChannel(1)) - with builder.align_left(): - builder.play( - library.Drag(160, 0.3, 40, 1.5), - channels.DriveChannel(0), - ) - builder.play( - library.Drag(320, 0.2, 80, 1.5), - channels.DriveChannel(1), - ) - builder.play( - library.Drag(480, 0.1, 120, 1.5), - channels.DriveChannel(2), - ) - builder.reference("sub") - with builder.align_left(): - for i in range(3): - builder.play( - library.GaussianSquare(1600, 0.1, 64, 1344), - channels.MeasureChannel(i), - ) - builder.acquire( - 1600, - channels.AcquireChannel(i), - channels.MemorySlot(i), - ) - - with builder.build() as subroutine: - for i in range(3): - samples = np.random.random(160) - builder.play(samples, channels.DriveChannel(i)) - schedule.assign_references({("sub",): subroutine}, inplace=True) - - return schedule - - -class ScheduleLoweringBench: - def setup(self): - self.schedule_block = build_complicated_schedule() - - def time_lowering(self): - # Lower schedule block to generate job payload - target_qobj_transform(self.schedule_block) From d3b8b918cd9856d2acff427f79ac3eb4e77d1a9a Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 3 Sep 2024 15:56:17 +0100 Subject: [PATCH 44/85] Avoid `ExtraInstructionAttributes` allocation on `unit="dt"` (#13078) The default value for `Instruction.unit` is `"dt"`. Previously, the `OperationFromPython` extraction logic would only suppress allocation of the extra instruction attributes if all the contained fields were `None`, but `None` is not actually a valid value of `Instruction.unit` (which must be a string). This meant that `OperationFromPython` would always allocate and store extra attributes, even for the default cases. This did not affect standard gates appended using their corresponding `QuantumCircuit` methods (since no Python-space extraction is performed in that case), but did affect standard calls to `append`, or anything else that entered from Python space. This drastically reduces the memory usage of circuits built by `append`-like methods. Ignoring the inefficiency factor of the heap-allocation implementation, this saves 66 bytes plus small-allocation overhead for 2-byte heap allocations (another 14 bytes on macOS, but will vary depending on the allocator) per standard instruction, which is on the order of 40% memory-usage reduction. --- crates/circuit/src/circuit_instruction.rs | 37 ++++++++++++++++++++--- crates/circuit/src/operations.rs | 2 +- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/crates/circuit/src/circuit_instruction.rs b/crates/circuit/src/circuit_instruction.rs index 215d337ab052..463f3352aa92 100644 --- a/crates/circuit/src/circuit_instruction.rs +++ b/crates/circuit/src/circuit_instruction.rs @@ -17,7 +17,7 @@ use numpy::IntoPyArray; use pyo3::basic::CompareOp; use pyo3::exceptions::{PyDeprecationWarning, PyTypeError}; use pyo3::prelude::*; -use pyo3::types::{PyList, PyTuple, PyType}; +use pyo3::types::{PyList, PyString, PyTuple, PyType}; use pyo3::{intern, IntoPy, PyObject, PyResult}; use smallvec::SmallVec; @@ -63,6 +63,20 @@ impl ExtraInstructionAttributes { None } } + + /// Get the Python-space version of the stored `unit`. This evalutes the Python-space default + /// (`"dt"`) value if we're storing a `None`. + pub fn py_unit(&self, py: Python) -> Py { + self.unit + .as_deref() + .map(|unit| <&str as IntoPy>>::into_py(unit, py)) + .unwrap_or_else(|| Self::default_unit(py).clone().unbind()) + } + + /// Get the Python-space default value for the `unit` field. + pub fn default_unit(py: Python) -> &Bound { + intern!(py, "dt") + } } /// A single instruction in a :class:`.QuantumCircuit`, comprised of the :attr:`operation` and @@ -267,10 +281,17 @@ impl CircuitInstruction { } #[getter] - fn unit(&self) -> Option<&str> { + fn unit(&self, py: Python) -> Py { + // Python space uses `"dt"` as the default, whereas we simply don't store the extra + // attributes at all if they're none. self.extra_attrs .as_ref() - .and_then(|attrs| attrs.unit.as_deref()) + .map(|attrs| attrs.py_unit(py)) + .unwrap_or_else(|| { + ExtraInstructionAttributes::default_unit(py) + .clone() + .unbind() + }) } /// Is the :class:`.Operation` contained in this instruction a Qiskit standard gate? @@ -524,10 +545,18 @@ impl<'py> FromPyObject<'py> for OperationFromPython { .map(|params| params.unwrap_or_default()) }; let extract_extra = || -> PyResult<_> { + let unit = { + // We accept Python-space `None` or `"dt"` as both meaning the default `"dt"`. + let raw_unit = ob.getattr(intern!(py, "unit"))?; + (!(raw_unit.is_none() + || raw_unit.eq(ExtraInstructionAttributes::default_unit(py))?)) + .then(|| raw_unit.extract::()) + .transpose()? + }; Ok(ExtraInstructionAttributes::new( ob.getattr(intern!(py, "label"))?.extract()?, ob.getattr(intern!(py, "duration"))?.extract()?, - ob.getattr(intern!(py, "unit"))?.extract()?, + unit, ob.getattr(intern!(py, "condition"))?.extract()?, ) .map(Box::from)) diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index f6e087a5680f..8cc2256af518 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -435,7 +435,7 @@ impl StandardGate { if let Some(extra) = extra_attrs { let kwargs = [ ("label", extra.label.to_object(py)), - ("unit", extra.unit.to_object(py)), + ("unit", extra.py_unit(py).into_any()), ("duration", extra.duration.to_object(py)), ] .into_py_dict_bound(py); From dff9e8121729d8273963eaf3a7d718c44f4cb31c Mon Sep 17 00:00:00 2001 From: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Date: Tue, 3 Sep 2024 18:06:48 -0400 Subject: [PATCH 45/85] Implement a capacity-allocated constructor for `DAGCircuit` in Rust. (#12975) * Initial: implement fixed capacity constructor for DAGCircuit - Implement `DAGCircuit` with `with_capacity` to create an initially allocated instance, for rust only. - Implement `with_capacity` for `BitData` and `IndexInterner` that creates an initally allocated instance of each type. - Other small tweaks and fixes. - Add num_edges optional argument. If known, use `num_edges` argument to create a `DAGCircuit` with the exact number of edges. - Leverage usage of new method in `copy_empty_like`. - Use `..Default::default()` for `op_names` and `calibrations` fields in `DAGCircuit::with_capacity()` * Fix: Adapt to #13033 * Fix: Re-arrange the function arguments as per @mtreinish's review. - The order now follows: qubits, clbits, vars, num_ops, edges. As per [Matthew's comment](https://github.com/Qiskit/qiskit/pull/12975#discussion_r1742426093). --- crates/circuit/src/bit_data.rs | 9 ++++ crates/circuit/src/dag_circuit.rs | 72 ++++++++++++++++++++++++++++++- crates/circuit/src/interner.rs | 7 +++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/crates/circuit/src/bit_data.rs b/crates/circuit/src/bit_data.rs index 0c0b20a02522..6a8e4af6b920 100644 --- a/crates/circuit/src/bit_data.rs +++ b/crates/circuit/src/bit_data.rs @@ -95,6 +95,15 @@ where } } + pub fn with_capacity(py: Python<'_>, description: String, capacity: usize) -> Self { + BitData { + description, + bits: Vec::with_capacity(capacity), + indices: HashMap::with_capacity(capacity), + cached: PyList::empty_bound(py).unbind(), + } + } + /// Gets the number of bits. pub fn len(&self) -> usize { self.bits.len() diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index afe6797596d9..90a4c75408fa 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -1556,7 +1556,14 @@ def _format(operand): /// DAGCircuit: An empty copy of self. #[pyo3(signature = (*, vars_mode="alike"))] fn copy_empty_like(&self, py: Python, vars_mode: &str) -> PyResult { - let mut target_dag = DAGCircuit::new(py)?; + let mut target_dag = DAGCircuit::with_capacity( + py, + self.num_qubits(), + self.num_clbits(), + Some(self.num_vars()), + None, + None, + )?; target_dag.name = self.name.as_ref().map(|n| n.clone_ref(py)); target_dag.global_phase = self.global_phase.clone(); target_dag.duration = self.duration.as_ref().map(|d| d.clone_ref(py)); @@ -6156,6 +6163,69 @@ impl DAGCircuit { } Ok(()) } + + /// Alternative constructor, builds a DAGCircuit with a fixed capacity. + /// + /// # Arguments: + /// - `py`: Python GIL token + /// - `num_qubits`: Number of qubits in the circuit + /// - `num_clbits`: Number of classical bits in the circuit. + /// - `num_vars`: (Optional) number of variables in the circuit. + /// - `num_ops`: (Optional) number of operations in the circuit. + /// - `num_edges`: (Optional) If known, number of edges in the circuit. + pub fn with_capacity( + py: Python, + num_qubits: usize, + num_clbits: usize, + num_vars: Option, + num_ops: Option, + num_edges: Option, + ) -> PyResult { + let num_ops: usize = num_ops.unwrap_or_default(); + let num_vars = num_vars.unwrap_or_default(); + let num_edges = num_edges.unwrap_or( + num_qubits + // 1 edge between the input node and the output node or 1st op node. + num_clbits + // 1 edge between the input node and the output node or 1st op node. + num_vars + // 1 edge between the input node and the output node or 1st op node. + num_ops, // In Average there will be 3 edges (2 qubits and 1 clbit, or 3 qubits) per op_node. + ); + + let num_nodes = num_qubits * 2 + // One input + One output node per qubit + num_clbits * 2 + // One input + One output node per clbit + num_vars * 2 + // One input + output node per variable + num_ops; + + Ok(Self { + name: None, + metadata: Some(PyDict::new_bound(py).unbind().into()), + calibrations: HashMap::default(), + dag: StableDiGraph::with_capacity(num_nodes, num_edges), + qregs: PyDict::new_bound(py).unbind(), + cregs: PyDict::new_bound(py).unbind(), + qargs_interner: Interner::with_capacity(num_qubits), + cargs_interner: Interner::with_capacity(num_clbits), + qubits: BitData::with_capacity(py, "qubits".to_string(), num_qubits), + clbits: BitData::with_capacity(py, "clbits".to_string(), num_clbits), + global_phase: Param::Float(0.), + duration: None, + unit: "dt".to_string(), + qubit_locations: PyDict::new_bound(py).unbind(), + clbit_locations: PyDict::new_bound(py).unbind(), + qubit_io_map: Vec::with_capacity(num_qubits), + clbit_io_map: Vec::with_capacity(num_clbits), + var_input_map: _VarIndexMap::new(py), + var_output_map: _VarIndexMap::new(py), + op_names: IndexMap::default(), + control_flow_module: PyControlFlowModule::new(py)?, + vars_info: HashMap::with_capacity(num_vars), + vars_by_type: [ + PySet::empty_bound(py)?.unbind(), + PySet::empty_bound(py)?.unbind(), + PySet::empty_bound(py)?.unbind(), + ], + }) + } + /// Get qargs from an intern index pub fn get_qargs(&self, index: Interned<[Qubit]>) -> &[Qubit] { self.qargs_interner.get(index) diff --git a/crates/circuit/src/interner.rs b/crates/circuit/src/interner.rs index 39c5364aa1cc..a8ac269b1a18 100644 --- a/crates/circuit/src/interner.rs +++ b/crates/circuit/src/interner.rs @@ -125,6 +125,13 @@ where _type: PhantomData, } } + + pub fn with_capacity(capacity: usize) -> Self { + Self(IndexSet::with_capacity_and_hasher( + capacity, + ::ahash::RandomState::new(), + )) + } } impl Interner From 576efcf14a4be392cbcdb3c75d2838a440f73b13 Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Wed, 4 Sep 2024 18:32:52 +0300 Subject: [PATCH 46/85] Bug fix in `HoareOptimizer` (#13083) * bug fix, test, reno * suggestions from code review; lint --- .../passes/optimization/hoare_opt.py | 20 ++++++----- .../notes/fix-hoare-opt-56d1ca6a07f07a2d.yaml | 5 +++ test/python/transpiler/test_hoare_opt.py | 35 +++++++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/fix-hoare-opt-56d1ca6a07f07a2d.yaml diff --git a/qiskit/transpiler/passes/optimization/hoare_opt.py b/qiskit/transpiler/passes/optimization/hoare_opt.py index a77f1985f696..e47074fc6142 100644 --- a/qiskit/transpiler/passes/optimization/hoare_opt.py +++ b/qiskit/transpiler/passes/optimization/hoare_opt.py @@ -203,20 +203,24 @@ def _traverse_dag(self, dag): """ import z3 - for node in dag.topological_op_nodes(): + # Pre-generate all DAG nodes, since we later iterate over them, while + # potentially modifying and removing some of them. + nodes = list(dag.topological_op_nodes()) + for node in nodes: gate = node.op - ctrlqb, ctrlvar, trgtqb, trgtvar = self._seperate_ctrl_trgt(node) + _, ctrlvar, trgtqb, trgtvar = self._seperate_ctrl_trgt(node) ctrl_ones = z3.And(*ctrlvar) - remove_ctrl, new_dag, qb_idx = self._remove_control(gate, ctrlvar, trgtvar) + remove_ctrl, new_dag, _ = self._remove_control(gate, ctrlvar, trgtvar) if remove_ctrl: - dag.substitute_node_with_dag(node, new_dag) - gate = gate.base_gate - node.op = gate.to_mutable() - node.name = gate.name - node.qargs = tuple((ctrlqb + trgtqb)[qi] for qi in qb_idx) + # We are replacing a node by a new node over a smaller number of qubits. + # This can be done using substitute_node_with_dag, which furthermore returns + # a mapping from old node ids to new nodes. + mapped_nodes = dag.substitute_node_with_dag(node, new_dag) + node = next(iter(mapped_nodes.values())) + gate = node.op _, ctrlvar, trgtqb, trgtvar = self._seperate_ctrl_trgt(node) ctrl_ones = z3.And(*ctrlvar) diff --git a/releasenotes/notes/fix-hoare-opt-56d1ca6a07f07a2d.yaml b/releasenotes/notes/fix-hoare-opt-56d1ca6a07f07a2d.yaml new file mode 100644 index 000000000000..7548dcc99564 --- /dev/null +++ b/releasenotes/notes/fix-hoare-opt-56d1ca6a07f07a2d.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed a bug in :class:`.HoareOptimizer` where a controlled gate was simplified + by removing its controls but the new gate was not handled correctly. diff --git a/test/python/transpiler/test_hoare_opt.py b/test/python/transpiler/test_hoare_opt.py index b3ae3df97678..ae2f9d9ae1e0 100644 --- a/test/python/transpiler/test_hoare_opt.py +++ b/test/python/transpiler/test_hoare_opt.py @@ -661,6 +661,41 @@ def test_multiple_pass(self): self.assertEqual(result2, circuit_to_dag(expected)) + def test_remove_control_then_identity(self): + """This first simplifies a gate by removing its control, then removes the + simplified gate by canceling it with another gate. + See: https://github.com/Qiskit/qiskit-terra/issues/13079 + """ + # ┌───┐┌───┐┌───┐ + # q_0: ┤ X ├┤ X ├┤ X ├ + # └─┬─┘└───┘└─┬─┘ + # q_1: ──■─────────┼── + # ┌───┐ │ + # q_2: ┤ X ├───────■── + # └───┘ + circuit = QuantumCircuit(3) + circuit.cx(1, 0) + circuit.x(2) + circuit.x(0) + circuit.cx(2, 0) + + simplified = HoareOptimizer()(circuit) + + # The CX(1, 0) gate is removed as the control qubit q_1 is initially 0. + # The CX(2, 0) gate is first replaced by X(0) gate as the control qubit q_2 is at 1, + # then the two X(0) gates are removed. + # + # q_0: ───── + # + # q_1: ───── + # ┌───┐ + # q_2: ┤ X ├ + # └───┘ + expected = QuantumCircuit(3) + expected.x(2) + + self.assertEqual(simplified, expected) + if __name__ == "__main__": unittest.main() From 05f64295ed8ab55a729cb0f81ff9662201e6f5e5 Mon Sep 17 00:00:00 2001 From: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:21:25 +0200 Subject: [PATCH 47/85] Oxidize Commutation Analysis (#12995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * init * up * lint * . * up * before cache * with cache * correct * cleaned up * lint reno * Update Cargo.lock * . * up * . * revert op * . * . * . * . * Delete Cargo.lock * . * corrected string comparison * removed Operator class from operation.rs * . * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * comments from code review * Port DAGCircuit to Rust This commit migrates the entirety of the `DAGCircuit` class to Rust. It fully replaces the Python version of the class. The primary advantage of this migration is moving from a Python space rustworkx directed graph representation to a Rust space petgraph (the upstream library for rustworkx) directed graph. Moving the graph data structure to rust enables us to directly interact with the DAG directly from transpiler passes in Rust in the future. This will enable a significant speed-up in those transpiler passes. Additionally, this should also improve the memory footprint as the DAGCircuit no longer stores `DAGNode` instances, and instead stores a lighter enum NodeType, which simply contains a `PackedInstruction` or the wire objects directly. Internally, the new Rust-based `DAGCircuit` uses a `petgraph::StableGraph` with node weights of type `NodeType` and edge weights of type `Wire`. The NodeType enum contains variants for `QubitIn`, `QubitOut`, `ClbitIn`, `ClbitOut`, and `Operation`, which should save us from all of the `isinstance` checking previously needed when working with `DAGNode` Python instances. The `Wire` enum contains variants `Qubit`, `Clbit`, and `Var`. As the full Qiskit data model is not rust-native at this point while all the class code in the `DAGCircuit` exists in Rust now, there are still sections that rely on Python or actively run Python code via Rust to function. These typically involve anything that uses `condition`, control flow, classical vars, calibrations, bit/register manipulation, etc. In the future as we either migrate this functionality to Rust or deprecate and remove it this can be updated in place to avoid the use of Python. API access from Python-space remains in terms of `DAGNode` instances to maintain API compatibility with the Python implementation. However, internally, we convert to and deal in terms of NodeType. When the user requests a particular node via lookup or iteration, we inflate an ephemeral `DAGNode` based on the internal `NodeType` and give them that. This is very similar to what was done in #10827 when porting CircuitData to Rust. As part of this porting there are a few small differences to keep in mind with the new Rust implementation of DAGCircuit. The first is that the topological ordering is slightly different with the new DAGCircuit. Previously, the Python version of `DAGCircuit` using a lexicographical topological sort key which was basically `"0,1,0,2"` where the first `0,1` are qargs on qubit indices `0,1` for nodes and `0,2` are cargs on clbit indices `0,2`. However, the sort key has now changed to be `(&[Qubit(0), Qubit(1)], &[Clbit(0), Clbit(2)])` in rust in this case which for the most part should behave identically, but there are some edge cases that will appear where the sort order is different. It will always be a valid topological ordering as the lexicographical key is used as a tie breaker when generating a topological sort. But if you're relaying on the exact same sort order there will be differences after this PR. The second is that a lot of undocumented functionality in the DAGCircuit which previously worked because of Python's implicit support for interacting with data structures is no longer functional. For example, previously the `DAGCircuit.qubits` list could be set directly (as the circuit visualizers previously did), but this was never documented as supported (and would corrupt the DAGCircuit). Any functionality like this we'd have to explicit include in the Rust implementation and as they were not included in the documented public API this PR opted to remove the vast majority of this type of functionality. The last related thing might require future work to mitigate is that this PR breaks the linkage between `DAGNode` and the underlying `DAGCirucit` object. In the Python implementation the `DAGNode` objects were stored directly in the `DAGCircuit` and when an API method returned a `DAGNode` from the DAG it was a shared reference to the underlying object in the `DAGCircuit`. This meant if you mutated the `DAGNode` it would be reflected in the `DAGCircuit`. This was not always a sound usage of the API as the `DAGCircuit` was implicitly caching many attributes of the DAG and you should always be using the `DAGCircuit` API to mutate any nodes to prevent any corruption of the `DAGCircuit`. However, now as the underlying data store for nodes in the DAG are no longer the python space objects returned by `DAGCircuit` methods mutating a `DAGNode` will not make any change in the underlying `DAGCircuit`. This can come as quite the surprise at first, especially if you were relying on this side effect, even if it was unsound. It's also worth noting that 2 large pieces of functionality from rustworkx are included in this PR. These are the new files `rustworkx_core_vnext` and `dot_utils` which are rustworkx's VF2 implementation and its dot file generation. As there was not a rust interface exposed for this functionality from rustworkx-core there was no way to use these functions in rustworkx. Until these interfaces added to rustworkx-core in future releases we'll have to keep these local copies. The vf2 implementation is in progress in Qiskit/rustworkx#1235, but `dot_utils` might make sense to keep around longer term as it is slightly modified from the upstream rustworkx implementation to directly interface with `DAGCircuit` instead of a generic graph. Co-authored-by: Matthew Treinish Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Alexander Ivrii Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Co-authored-by: John Lapeyre Co-authored-by: Jake Lishman * Update visual mpl circuit drawer references Right now there is a bug in the matplotlib circuit visualizer likely caused by the new `__eq__` implementation for `DAGOpNode` that didn't exist before were some gates are missing from the visualization. In the interest of unblocking this PR this commit updates the references for these cases temporarily until this issue is fixed. * Ensure DAGNode.sort_key is always a string Previously the sort_key attribute of the Python space DAGCircuit was incorrectly being set to `None` for rust generated node objects. This was done as for the default path the sort key is determined from the rust domain's representation of qubits and there is no analogous data in the Python object. However, this was indavertandly a breaking API change as sort_key is expected to always be a string. This commit adds a default string to use for all node types so that we always have a reasonable value that matches the typing of the class. A future step is likely to add back the `dag` kwarg to the node types and generate the string on the fly from the rust space data. * Make Python argument first in Param::eq and Param::is_close The standard function signature convention for functions that take a `py: Python` argument is to make the Python argument the first (or second after `&self`). The `Param::eq` and `Param::is_close` methods were not following this convention and had `py` as a later argument in the signature. This commit corrects the oversight. * Fix merge conflict with #12943 With the recent merge with main we pulled in #12943 which conflicted with the rust space API changes made in this PR branch. This commit updates the usage to conform with the new interface introduced in this PR. * Add release notes and test for invalid args on apply methods This commit adds several release notes to document this change. This includes a feature note to describe the high level change and the user facing benefit (mainly reduced memory consumption for DAGCircuits), two upgrade notes to document the differences with shared references caused by the new data structure, and a fix note documenting the fix for how qargs and cargs are handled on `.apply_operation_back()` and `.apply_operation_front()`. Along with the fix note a new unit test is added to serve as a regression test so that we don't accidentally allow adding cargs as qargs and vice versa in the future. * Restore `inplace` argument functionality for substitute_node() This commit restores the functionality of the `inplace` argument for `substitute_node()` and restores the tests validating the object identity when using the flag. This flag was originally excluded from the implementation because the Rust representation of the dag is not a shared reference with Python space and the flag doesn't really mean the same thing as there is always a second copy of the data for Python space now. The implementation here is cheating slighty as we're passed in the DAG node by reference it relies on that reference to update the input node at the same time we update the dag. Unlike the previous Python implementation where we were updating the node in place and the `inplace` argument was slightly faster because everything was done by reference. The rust space data is still a compressed copy of the data we return to Python so the `inplace` flag will be slightly more inefficient as we need to copy to update the Python space representation in addition to the rust version. * Revert needless dict() cast on metadata in dag_to_circuit() This commit removes an unecessary `dict()` cast on the `dag.metadata` when setting it on `QuantumCircuit.metadata` in `qiskit.converters.dag_to_circuit()`. This slipped in at some point during the development of this PR and it's not clear why, but it isn't needed so this removes it. * Add code comment for DAGOpNode.__eq__ parameter checking This commit adds a small inline code comment to make it clear why we skip parameter comparisons in DAGOpNode.__eq__ for python ops. It might not be clear why the value is hard coded to `true` in this case, as this check is done via Python so we don't need to duplicate it in rust space. * Raise a ValueError on DAGNode creation with invalid index This commit adds error checking to the DAGNode constructor to raise a PyValueError if the input index is not valid (any index < -1). Previously this would have panicked instead of raising a user catchable error. * Use macro argument to set python getter/setter name This commit updates the function names for `get__node_id` and `set__node_id` method to use a name that clippy is happy with and leverage the pyo3 macros to set the python space name correctly instead of using the implicit naming rules. * Remove Ord and PartialOrd derives from interner::Index The Ord and PartialOrd traits were originally added to the Index struct so they could be used for the sort key in lexicographical topological sorting. However, that approach was abandonded during the development of this PR and instead the expanded Qubit and Clbit indices were used instead. This left the ordering traits as unnecessary on Index and potentially misleading. This commit just opts to remove them as they're not needed anymore. * Fix missing nodes in matplotlib drawer. Previously, the change in equality for DAGNodes was causing nodes to clobber eachother in the matplotlib drawer's tracking data structures when used as keys to maps. To fix this, we ensure that all nodes have a unique ID across layers before constructing the matplotlib drawer. They actually of course _do_ in the original DAG, but we don't really care what the original IDs are, so we just make them up. Writing to _node_id on a DAGNode may seem odd, but it exists in the old Python API (prior to being ported to Rust) and doesn't actually mutate the DAG at all since DAGNodes are ephemeral. * Revert "Update visual mpl circuit drawer references" With the previous commit the bug in the matplotlib drawer causing the images to diverge should be fixed. This commit reverts the change to the reference images as there should be no difference now. This reverts commit 1e4e6f386286b0b4e7f3ebd3f706f948dd707575. * Update visual mpl circuit drawer references for control flow circuits The earlier commit that "fixed" the drawers corrected the visualization to match expectations in most cases. However after restoring the references to what's on main several comparison tests with control flow in the circuit were still failing. The failure mode looks similar to the other cases, but across control flow blocks instead of at the circuit level. This commit temporarily updates the references of these to the state of what is generated currently to unblock CI. If/when we have a fix this commit can be reverted. * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * code review * Fix edge cases in DAGOpNode.__eq__ This commit fixes a couple of edge cases in DAGOpNode.__eq__ method around the python interaction for the method. The first is that in the case where we had python object parameter types for the gates we weren't comparing them at all. This is fixed so we use python object equality for the params in this case. Then we were dropping the error handling in the case of using python for equality, this fixes it to return the error to users if the equality check fails. Finally a comment is added to explain the expected use case for `DAGOpNode.__eq__` and why parameter checking is more strict than elsewhere. * Remove Param::add() for global phase addition This commit removes the Param::add() method and instead adds a local private function to the `dag_circuit` module for doing global phase addition. Previously the `Param::add()` method was used solely for adding global phase in `DAGCircuit` and it took some shortcuts knowing that context. This made the method implementation ill suited as a general implementation. * More complete fix for matplotlib drawer. * Revert "Update visual mpl circuit drawer references for control flow circuits" This reverts commit 9a6f9536a3a7412d19a9fd9bbd761825c9a53d0f. * Unify rayon versions in workspace * Remove unused _GLOBAL_NID. * Use global monotonic ID counter for ids in drawer The fundamental issue with matplotlib visualizations of control flow is that locally in the control flow block the nodes look the same but are stored in an outer circuit dictionary. If the gates are the same and on the same qubits and happen to have the same node id inside the different control flow blocks the drawer would think it's already drawn the node and skip it incorrectly. The previous fix for this didn't go far enough because it wasn't accounting for the recursive execution of the drawer for inner blocks (it also didn't account for LayerSpoolers of the same length). * Remove unused BitData iterator stuff. * Fully port Optimize1qGatesDecomposition to Rust This commit builds off of #12550 and the other data model in Rust infrastructure and migrates the Optimize1qGatesDecomposition pass to operate fully in Rust. The full path of the transpiler pass now never leaves rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly calibrations and parameter expressions (for global phase). But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to be a single for loop in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done by the pass so we should be able to the throughput of the pass by leveraging multithreading to handle each run in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that (this pass is a good candidate to work through the bugs on that). Part of #12208 * remove with_gil in favor of passing python tokens as params * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * fmt * python serialization * deprecation * Update commutation_checker.py * heh * init * let Pytuple collect * lint * First set of comments - use Qubit/Clbit - more info on unsafe - update reno - use LazySet less - use OperationRef, avoid CircuitInstruction creation * Second part - clippy - no BigInt - more comments * Matrix speed & fix string sort -- could not use op.name() directly since sorted differently than Python, hence it's back to BigInt * have the Python implementation use Rust * lint & tools * remove unsafe blocks * One more try to avoid segfaulty windows -- if that doesn't work maybe revert the change the the Py CommChecker uses Rust * Original version Co-authored-by: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com> * Sync with updated CommutationChecker todo: shouldn't make the qubits interner public * Debug: disable cache trying to figure out why the windows CI fails (after being unable to locally reproduce we're using CI with a reduced set of tests) * ... second try * Update crates/accelerate/src/commutation_checker.rs Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * Restore azure config * Remove unused import * Revert "Debug: disable cache" This reverts commit c564b806c9ff31d5faa6aa3f02c18cfe6a5ff2c5. * Don't overallocate cache We were allocating a the cache hashmap with a capacity for max cache size entries every time we instantiated a new CommutationChecker. The max cache size is 1 million. This meant we were allocating 162MB everytime CommutationChecker.__new__ was called, which includes each time we instantiate it manually (which happens once on import), the CommutationAnalysis pass gets instantiated (twice per preset pass manager created with level 2 or 3), or a commutation checker instance is pickle deserialized. This ends up causing a fairly large memory regression and is the source of the CI failures on windows. Co-authored-by: Jake Lishman * Cleanup parameter key type to handle edge conditions better This commit cleans up the ParameterKey type and usage to make it handle edge conditions better. The first is that the type just doesn't do the right thing for NaN, -0, or the infinities. Canonicalization is added for hash on -0 and the only constructor of the newtype adds a runtime guard against NaN and inifinity (positive or negative) to avoid that issue. The approach only makes sense as the cache is really there to guard us against unnecessary re-computing when we reiterate over the circuit > 1 time and nothing has changed for gates. Otherwise comparing floats like done in this PR does would not be a sound or an effective approach. * Remove unnecessary cache hit rate tracking * Undo test assertion changes * Undo unrelated test changes * Undo pending deprecation and unify commutation classes This commit removes the pending deprecation decorator from the python class definition as the Python class just internally is using the rust implementation now. This also removes directly using the rust implementation for the standard commutation library global as using the python class is exactly the same now. We can revisit if there is anything we want to deprecate and remove in 2.0 in a follow up PR. Personally, I think the cache management methods are all we really want to remove as the cache should be an internal implementation detail and not part of the public interface. * Undo gha config changes * Make serialization explicit This commit makes the pickling of cache entries explicit. Previously it was relying on conversion traits which hid some of the complexity but this uses a pair of conversion functions instead. * Remove stray SAFETY comment * Remove ddt usage from the tests Now that the python commutation checker and the rust commutation checker are the same thing the ddt parameterization of the commutation checker tests was unecessary duplication. This commit removes the ddt usage to restore having a single run of all the tests. * Update release note * Fix CommutationChecker class import * Remove invalid test assertion for no longer public attribute * Ray's review comments Co-authored-by: Raynel Sanchez * Handle ``atol/rtol``, more error propagation * update to latest changes in commchecker * fix merge conflict remnants * re-use expensive quantities such as the relative placement and the parameter hash * add missing header * gentler error handling * review comments & more docs * Use vec over IndexSet + clippy - vec is slightly faster than vec - add custom types to satisfies clippy's complex type complaint - don't handle Clbit/Var * Simplify python class construction Since this PR was first written the split between the python side and rust side of the CommutationChecker class has changed so that there are no longer separate classes anymore. The implementations are unified and the python space class just wraps an inner rust object. However, the construction of the CommutationAnalysis pass was still written assuming there was the possibility to get either a rust or Python object. This commit fixes this and the type change on the `comm_checker` attribute by removing the unnecessary logic. --------- Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Co-authored-by: Kevin Hartman Co-authored-by: Matthew Treinish Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Alexander Ivrii Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Co-authored-by: John Lapeyre Co-authored-by: Jake Lishman Co-authored-by: Julien Gacon Co-authored-by: Raynel Sanchez --- crates/accelerate/src/commutation_analysis.rs | 192 ++++++++++++++++++ crates/accelerate/src/commutation_checker.rs | 4 +- crates/accelerate/src/lib.rs | 1 + crates/circuit/src/dag_circuit.rs | 2 +- crates/pyext/src/lib.rs | 19 +- qiskit/__init__.py | 1 + .../optimization/commutation_analysis.py | 52 +---- ...commutation-analysis-d2fc81feb6ca80aa.yaml | 4 + 8 files changed, 214 insertions(+), 61 deletions(-) create mode 100644 crates/accelerate/src/commutation_analysis.rs create mode 100644 releasenotes/notes/oxidize-commutation-analysis-d2fc81feb6ca80aa.yaml diff --git a/crates/accelerate/src/commutation_analysis.rs b/crates/accelerate/src/commutation_analysis.rs new file mode 100644 index 000000000000..08fa1dda5ec9 --- /dev/null +++ b/crates/accelerate/src/commutation_analysis.rs @@ -0,0 +1,192 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use pyo3::exceptions::PyValueError; +use pyo3::prelude::PyModule; +use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyResult, Python}; +use qiskit_circuit::Qubit; + +use crate::commutation_checker::CommutationChecker; +use hashbrown::HashMap; +use pyo3::prelude::*; + +use pyo3::types::{PyDict, PyList}; +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType, Wire}; +use rustworkx_core::petgraph::stable_graph::NodeIndex; + +// Custom types to store the commutation sets and node indices, +// see the docstring below for more information. +type CommutationSet = HashMap>>; +type NodeIndices = HashMap<(NodeIndex, Wire), usize>; + +// the maximum number of qubits we check commutativity for +const MAX_NUM_QUBITS: u32 = 3; + +/// Compute the commutation sets for a given DAG. +/// +/// We return two HashMaps: +/// * {wire: commutation_sets}: For each wire, we keep a vector of index sets, where each index +/// set contains mutually commuting nodes. Note that these include the input and output nodes +/// which do not commute with anything. +/// * {(node, wire): index}: For each (node, wire) pair we store the index indicating in which +/// commutation set the node appears on a given wire. +/// +/// For example, if we have a circuit +/// +/// |0> -- X -- SX -- Z (out) +/// 0 2 3 4 1 <-- node indices including input (0) and output (1) nodes +/// +/// Then we would have +/// +/// commutation_set = {0: [[0], [2, 3], [4], [1]]} +/// node_indices = {(0, 0): 0, (1, 0): 3, (2, 0): 1, (3, 0): 1, (4, 0): 2} +/// +fn analyze_commutations_inner( + py: Python, + dag: &mut DAGCircuit, + commutation_checker: &mut CommutationChecker, +) -> PyResult<(CommutationSet, NodeIndices)> { + let mut commutation_set: CommutationSet = HashMap::new(); + let mut node_indices: NodeIndices = HashMap::new(); + + for qubit in 0..dag.num_qubits() { + let wire = Wire::Qubit(Qubit(qubit as u32)); + + for current_gate_idx in dag.nodes_on_wire(py, &wire, false) { + // get the commutation set associated with the current wire, or create a new + // index set containing the current gate + let commutation_entry = commutation_set + .entry(wire.clone()) + .or_insert_with(|| vec![vec![current_gate_idx]]); + + // we can unwrap as we know the commutation entry has at least one element + let last = commutation_entry.last_mut().unwrap(); + + // if the current gate index is not in the set, check whether it commutes with + // the previous nodes -- if yes, add it to the commutation set + if !last.contains(¤t_gate_idx) { + let mut all_commute = true; + + for prev_gate_idx in last.iter() { + // if the node is an input/output node, they do not commute, so we only + // continue if the nodes are operation nodes + if let (NodeType::Operation(packed_inst0), NodeType::Operation(packed_inst1)) = + (&dag.dag[current_gate_idx], &dag.dag[*prev_gate_idx]) + { + let op1 = packed_inst0.op.view(); + let op2 = packed_inst1.op.view(); + let params1 = packed_inst0.params_view(); + let params2 = packed_inst1.params_view(); + let qargs1 = dag.get_qargs(packed_inst0.qubits); + let qargs2 = dag.get_qargs(packed_inst1.qubits); + let cargs1 = dag.get_cargs(packed_inst0.clbits); + let cargs2 = dag.get_cargs(packed_inst1.clbits); + + all_commute = commutation_checker.commute_inner( + py, + &op1, + params1, + packed_inst0.extra_attrs.as_deref(), + qargs1, + cargs1, + &op2, + params2, + packed_inst1.extra_attrs.as_deref(), + qargs2, + cargs2, + MAX_NUM_QUBITS, + )?; + if !all_commute { + break; + } + } else { + all_commute = false; + break; + } + } + + if all_commute { + // all commute, add to current list + last.push(current_gate_idx); + } else { + // does not commute, create new list + commutation_entry.push(vec![current_gate_idx]); + } + } + + node_indices.insert( + (current_gate_idx, wire.clone()), + commutation_entry.len() - 1, + ); + } + } + + Ok((commutation_set, node_indices)) +} + +#[pyfunction] +#[pyo3(signature = (dag, commutation_checker))] +pub(crate) fn analyze_commutations( + py: Python, + dag: &mut DAGCircuit, + commutation_checker: &mut CommutationChecker, +) -> PyResult> { + // This returns two HashMaps: + // * The commuting nodes per wire: {wire: [commuting_nodes_1, commuting_nodes_2, ...]} + // * The index in which commutation set a given node is located on a wire: {(node, wire): index} + // The Python dict will store both of these dictionaries in one. + let (commutation_set, node_indices) = analyze_commutations_inner(py, dag, commutation_checker)?; + + let out_dict = PyDict::new_bound(py); + + // First set the {wire: [commuting_nodes_1, ...]} bit + for (wire, commutations) in commutation_set { + // we know all wires are of type Wire::Qubit, since in analyze_commutations_inner + // we only iterater over the qubits + let py_wire = match wire { + Wire::Qubit(q) => dag.qubits.get(q).unwrap().to_object(py), + _ => return Err(PyValueError::new_err("Unexpected wire type.")), + }; + + out_dict.set_item( + py_wire, + PyList::new_bound( + py, + commutations.iter().map(|inner| { + PyList::new_bound( + py, + inner + .iter() + .map(|node_index| dag.get_node(py, *node_index).unwrap()), + ) + }), + ), + )?; + } + + // Then we add the {(node, wire): index} dictionary + for ((node_index, wire), index) in node_indices { + let py_wire = match wire { + Wire::Qubit(q) => dag.qubits.get(q).unwrap().to_object(py), + _ => return Err(PyValueError::new_err("Unexpected wire type.")), + }; + out_dict.set_item((dag.get_node(py, node_index)?, py_wire), index)?; + } + + Ok(out_dict.unbind()) +} + +#[pymodule] +pub fn commutation_analysis(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(analyze_commutations))?; + Ok(()) +} diff --git a/crates/accelerate/src/commutation_checker.rs b/crates/accelerate/src/commutation_checker.rs index 6fd9d58a7c23..b00d7c624c92 100644 --- a/crates/accelerate/src/commutation_checker.rs +++ b/crates/accelerate/src/commutation_checker.rs @@ -69,7 +69,7 @@ where /// lookups. It's not meant to be a public facing Python object though and only used /// internally by the Python class. #[pyclass(module = "qiskit._accelerate.commutation_checker")] -struct CommutationChecker { +pub struct CommutationChecker { library: CommutationLibrary, cache_max_entries: usize, cache: HashMap<(String, String), CommutationCacheEntry>, @@ -227,7 +227,7 @@ impl CommutationChecker { impl CommutationChecker { #[allow(clippy::too_many_arguments)] - fn commute_inner( + pub fn commute_inner( &mut self, py: Python, op1: &OperationRef, diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 3a8c4bf51071..6561dd258614 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -15,6 +15,7 @@ use std::env; use pyo3::import_exception; pub mod circuit_library; +pub mod commutation_analysis; pub mod commutation_checker; pub mod convert_2q_block_matrix; pub mod dense_layout; diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 90a4c75408fa..fdaa81e3b4ca 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -5530,7 +5530,7 @@ impl DAGCircuit { /// Get the nodes on the given wire. /// /// Note: result is empty if the wire is not in the DAG. - fn nodes_on_wire(&self, py: Python, wire: &Wire, only_ops: bool) -> Vec { + pub fn nodes_on_wire(&self, py: Python, wire: &Wire, only_ops: bool) -> Vec { let mut nodes = Vec::new(); let mut current_node = match wire { Wire::Qubit(qubit) => self.qubit_io_map.get(qubit.0 as usize).map(|x| x[0]), diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 24a4badf6539..fdb2bff9a21d 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -13,15 +13,15 @@ use pyo3::prelude::*; use qiskit_accelerate::{ - circuit_library::circuit_library, commutation_checker::commutation_checker, - convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, - error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, - isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, - pauli_exp_val::pauli_expval, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, - sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, - stochastic_swap::stochastic_swap, synthesis::synthesis, target_transpiler::target, - two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, utils::utils, - vf2_layout::vf2_layout, + circuit_library::circuit_library, commutation_analysis::commutation_analysis, + commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, + dense_layout::dense_layout, error_map::error_map, + euler_one_qubit_decomposer::euler_one_qubit_decomposer, isometry::isometry, nlayout::nlayout, + optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, results::results, + sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, + star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, + target_transpiler::target, two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, + utils::utils, vf2_layout::vf2_layout, }; #[inline(always)] @@ -62,5 +62,6 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, utils, "utils")?; add_submodule(m, vf2_layout, "vf2_layout")?; add_submodule(m, commutation_checker, "commutation_checker")?; + add_submodule(m, commutation_analysis, "commutation_analysis")?; Ok(()) } diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 67384b38971a..38a9f5952425 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -87,6 +87,7 @@ sys.modules["qiskit._accelerate.synthesis.linear"] = _accelerate.synthesis.linear sys.modules["qiskit._accelerate.synthesis.clifford"] = _accelerate.synthesis.clifford sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker +sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase from qiskit.exceptions import QiskitError, MissingOptionalLibraryError diff --git a/qiskit/transpiler/passes/optimization/commutation_analysis.py b/qiskit/transpiler/passes/optimization/commutation_analysis.py index 12ed7145eec7..d801e4775937 100644 --- a/qiskit/transpiler/passes/optimization/commutation_analysis.py +++ b/qiskit/transpiler/passes/optimization/commutation_analysis.py @@ -12,11 +12,9 @@ """Analysis pass to find commutation relations between DAG nodes.""" -from collections import defaultdict - from qiskit.circuit.commutation_library import SessionCommutationChecker as scc -from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler.basepasses import AnalysisPass +from qiskit._accelerate.commutation_analysis import analyze_commutations class CommutationAnalysis(AnalysisPass): @@ -33,6 +31,7 @@ def __init__(self, *, _commutation_checker=None): # do not care about commutations of all gates, but just a subset if _commutation_checker is None: _commutation_checker = scc + self.comm_checker = _commutation_checker def run(self, dag): @@ -42,49 +41,4 @@ def run(self, dag): into the ``property_set``. """ # Initiate the commutation set - self.property_set["commutation_set"] = defaultdict(list) - - # Build a dictionary to keep track of the gates on each qubit - # The key with format (wire) will store the lists of commutation sets - # The key with format (node, wire) will store the index of the commutation set - # on the specified wire, thus, for example: - # self.property_set['commutation_set'][wire][(node, wire)] will give the - # commutation set that contains node. - - for wire in dag.qubits: - self.property_set["commutation_set"][wire] = [] - - # Add edges to the dictionary for each qubit - for node in dag.topological_op_nodes(): - for _, _, edge_wire in dag.edges(node): - self.property_set["commutation_set"][(node, edge_wire)] = -1 - - # Construct the commutation set - for wire in dag.qubits: - - for current_gate in dag.nodes_on_wire(wire): - - current_comm_set = self.property_set["commutation_set"][wire] - if not current_comm_set: - current_comm_set.append([current_gate]) - - if current_gate not in current_comm_set[-1]: - does_commute = True - - # Check if the current gate commutes with all the gates in the current block - for prev_gate in current_comm_set[-1]: - does_commute = ( - isinstance(current_gate, DAGOpNode) - and isinstance(prev_gate, DAGOpNode) - and self.comm_checker.commute_nodes(current_gate, prev_gate) - ) - if not does_commute: - break - - if does_commute: - current_comm_set[-1].append(current_gate) - else: - current_comm_set.append([current_gate]) - - temp_len = len(current_comm_set) - self.property_set["commutation_set"][(current_gate, wire)] = temp_len - 1 + self.property_set["commutation_set"] = analyze_commutations(dag, self.comm_checker.cc) diff --git a/releasenotes/notes/oxidize-commutation-analysis-d2fc81feb6ca80aa.yaml b/releasenotes/notes/oxidize-commutation-analysis-d2fc81feb6ca80aa.yaml new file mode 100644 index 000000000000..967a65bcebab --- /dev/null +++ b/releasenotes/notes/oxidize-commutation-analysis-d2fc81feb6ca80aa.yaml @@ -0,0 +1,4 @@ +--- +features_transpiler: + - | + Added a Rust implementation of :class:`.CommutationAnalysis` in :func:`.analyze_commutations`. From 52733ae09f7ac9d2d5e2a674970ff95301d34bd6 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 5 Sep 2024 04:20:32 -0400 Subject: [PATCH 48/85] Adjust graphviz options for better layout with plot_gate_map() (#12770) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adjust graphviz options for better layout with plot_gate_map() This commit fixes an issue with the visualizations of some backends/coupling maps. The default neato settings worked well in most cases but for some graphs it was not generating a good layout. This tweaks the settings a bit so that layouts work with more classes of graphs. * Don't set graph attributes if qubit_coordinates is set * adjust sizes * planar branching * support for backendv1 * remove the formula * new ref images --------- Co-authored-by: Luciano Bello Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- qiskit/visualization/gate_map.py | 34 ++++++++++++++---- ...djust-neato-settings-3adcc0ae9e245ce9.yaml | 6 ++++ .../graph/references/16_qubit_gate_map.png | Bin 37221 -> 26909 bytes .../graph/references/27_qubit_gate_map.png | Bin 54334 -> 39631 bytes .../mpl/graph/references/5_qubit_gate_map.png | Bin 8766 -> 8722 bytes .../graph/references/65_qubit_gate_map.png | Bin 135197 -> 98456 bytes .../mpl/graph/references/7_qubit_gate_map.png | Bin 12001 -> 9122 bytes .../graph/references/bloch_multivector.png | Bin 72475 -> 72475 bytes ...bloch_multivector_figsize_improvements.png | Bin 70591 -> 70588 bytes test/visual/mpl/graph/references/figsize.png | Bin 8766 -> 8722 bytes .../mpl/graph/references/font_color.png | Bin 136101 -> 100497 bytes test/visual/mpl/graph/references/hinton.png | Bin 6395 -> 6395 bytes .../visual/mpl/graph/references/histogram.png | Bin 9520 -> 10300 bytes .../references/histogram_2_sets_with_rest.png | Bin 10759 -> 12343 bytes .../mpl/graph/references/histogram_color.png | Bin 9576 -> 10353 bytes .../references/histogram_desc_value_sort.png | Bin 14378 -> 18290 bytes .../graph/references/histogram_hamming.png | Bin 11864 -> 12642 bytes .../mpl/graph/references/histogram_legend.png | Bin 12162 -> 14197 bytes .../references/histogram_multiple_colors.png | Bin 10558 -> 13587 bytes .../mpl/graph/references/histogram_title.png | Bin 10495 -> 12343 bytes .../graph/references/histogram_value_sort.png | Bin 14301 -> 18148 bytes .../graph/references/histogram_with_rest.png | Bin 9881 -> 10806 bytes .../mpl/graph/references/line_color.png | Bin 144577 -> 105685 bytes test/visual/mpl/graph/references/paulivec.png | Bin 17133 -> 17133 bytes test/visual/mpl/graph/references/qsphere.png | Bin 40227 -> 40227 bytes .../mpl/graph/references/qubit_color.png | Bin 12473 -> 9581 bytes .../mpl/graph/references/qubit_labels.png | Bin 11018 -> 8830 bytes .../mpl/graph/references/qubit_size.png | Bin 9109 -> 10307 bytes .../mpl/graph/references/state_city.png | Bin 106823 -> 108666 bytes .../mpl/graph/test_graph_matplotlib_drawer.py | 12 +++---- 30 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 releasenotes/notes/adjust-neato-settings-3adcc0ae9e245ce9.yaml diff --git a/qiskit/visualization/gate_map.py b/qiskit/visualization/gate_map.py index b950c84c902a..eb20623f0c8c 100644 --- a/qiskit/visualization/gate_map.py +++ b/qiskit/visualization/gate_map.py @@ -945,6 +945,7 @@ def plot_gate_map( font_color, ax, filename, + planar=rx.is_planar(coupling_map.graph.to_undirected(multigraph=False)), ) @@ -966,6 +967,8 @@ def plot_coupling_map( font_color="white", ax=None, filename=None, + *, + planar=True, ): """Plots an arbitrary coupling map of qubits (embedded in a plane). @@ -987,6 +990,7 @@ def plot_coupling_map( font_color (str): The font color for the qubit labels. ax (Axes): A Matplotlib axes instance. filename (str): file path to save image to. + planar (bool): If the coupling map is planar or not. Default: ``True`` (i.e. it is planar) Returns: Figure: A Matplotlib figure instance. @@ -1057,7 +1061,14 @@ def plot_coupling_map( if font_size is None: max_characters = max(1, max(len(str(x)) for x in qubit_labels)) - font_size = max(int(20 / max_characters), 1) + if max_characters == 1: + font_size = 20 + elif max_characters == 2: + font_size = 14 + elif max_characters == 3: + font_size = 12 + else: + font_size = 1 def color_node(node): if qubit_coordinates: @@ -1065,8 +1076,6 @@ def color_node(node): "label": str(qubit_labels[node]), "color": f'"{qubit_color[node]}"', "fillcolor": f'"{qubit_color[node]}"', - "style": "filled", - "shape": "circle", "pos": f'"{qubit_coordinates[node][0]},{qubit_coordinates[node][1]}"', "pin": "True", } @@ -1075,11 +1084,11 @@ def color_node(node): "label": str(qubit_labels[node]), "color": f'"{qubit_color[node]}"', "fillcolor": f'"{qubit_color[node]}"', - "style": "filled", - "shape": "circle", } + out_dict["style"] = "filled" + out_dict["shape"] = "circle" out_dict["fontcolor"] = f'"{font_color}"' - out_dict["fontsize"] = str(font_size) + out_dict["fontsize"] = f'"{str(font_size)}!"' out_dict["height"] = str(qubit_size * px) out_dict["fixedsize"] = "True" out_dict["fontname"] = '"DejaVu Sans"' @@ -1093,9 +1102,22 @@ def color_edge(edge): } return out_dict + graph_attributes = None + if not qubit_coordinates: + if planar: + graph_attributes = { + "overlap_scaling": "-7", + "overlap": "prism", + "model": "subset", + } + else: + graph_attributes = { + "overlap": "true", + } plot = graphviz_draw( graph, method="neato", + graph_attr=graph_attributes, node_attr_fn=color_node, edge_attr_fn=color_edge, filename=filename, diff --git a/releasenotes/notes/adjust-neato-settings-3adcc0ae9e245ce9.yaml b/releasenotes/notes/adjust-neato-settings-3adcc0ae9e245ce9.yaml new file mode 100644 index 000000000000..9dec5debb2ef --- /dev/null +++ b/releasenotes/notes/adjust-neato-settings-3adcc0ae9e245ce9.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes an issue with the visualizations of some backends/coupling maps that showed as folded on their own. The + `default ``neato`` setting `_ works well in most cases. However, + ``prism`` overlap returns a more regular layout for other scenarios. diff --git a/test/visual/mpl/graph/references/16_qubit_gate_map.png b/test/visual/mpl/graph/references/16_qubit_gate_map.png index c76baabf152238ad114b5951d85f6c869cbd4d59..722b1db9152393ec37d2d13a02e72a2c4a4f0cf5 100644 GIT binary patch literal 26909 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 KVqb5I&-e$#QzRw; diff --git a/test/visual/mpl/graph/references/27_qubit_gate_map.png b/test/visual/mpl/graph/references/27_qubit_gate_map.png index 73ef08c1c3a8cee2440f2f2dca21e2407a805a04..59ed9d8d5cfc44274bfd534c5fb2e2592e36f9e5 100644 GIT binary patch literal 39631 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 *_p#WnJY{9aABnxpf329E z*}zy^maCrENGiVxvnuE^`YZpJZ@$*ErAcATbZ)ub2A2-H9vEcK_ezQ16IW4MqlO2U z?-SQ-oygs3I%TA6QND7Z|JUmc7Fuz1l~z_MC28V4G3IsBN5ojzzRl|dt$Af%3QDD5 zo3!rYN7bBla-KAeU#>0Y=EpX61!QV_r4jBt{)PR^b)J2LFogh@A7ehhm||;Tn~ESo?`?pE4y+D?1_+*kLmF z*bo94;$RLUR;#q(1j(ngh&aIBTnolM0va_uDXW|5RPkFp5R(-#0Sm4|u(S`kfr59c&Fy7OYYz68PfSJy zMIZ$^6%&h=22=X&b1OYQEscr?*pNKqEjd?&PwC-w5t~qn@nxKi$zd zC*9kMUgdBLoF6*?UKam>FBN=|9vo&=jSL~+saPM^+RY~`INu=^%qpjPeqFN8j;y17 zem$MaBW8O1;@Wb5+QZ#RZ)tT)H;at2g49;iS>7%=ZL*;0J~K7Hx-0n|uBL4;Az^Pg z_dEd&N8$wXoHbN$v-7GW_CYBDRDAb})miNOl1QD@f4Gd`%g@3Y#JJVJn76-5QkvUF zpZx%EmPKm_)aJI3WKBxpIsQJL36^}-&F79k0GQZQ6yQe7kC;-J86@|0VSGu<;{Oc7vBdeFiuA`?WWp6&i8loH*Qc0bvC&oKwYr7>?ZV?*nrE z!CXZR$5EXN2e1yEV#Thj!cojRZU)IQ>HU-Mzp>ig&j2EYR>gYYgjQaEBZm{Hx`8{Do- zkH@uG6gqE8N zkdJEdl(<&vkJZ`i9Bmn?glKwDw4%a(dAB!y?9CIvny%5ER@ezEOL?o7ss8nND1rrQ z(QJ6Ni0Ui8`M~9$VX)ktsW7lxXoFd=`Ct=yiim8)jWvb}@}= zBofgj0hbrS$h{fnW#v3Re1xKbCWGhLcV0&~e}5VDaAxMN zTPw&X?wKra30+-RotQcCkYjp?mn}3gO1^{aE~bq)1+!pFq!xP>}otBgPu{n*XI(WU?nCxn7wJjNFP(htPnVlDBeCf7?P z_#e42NmO0;BgAp=3-G_l)U^ByC5 z35xhw3)MUM_&VCe7^%O0Np3!NNCu1C1gUI=K;p*yClmmwL0ilC1%{UXllV~i{l%XT zC$jGUIFO`^PQC}aGwcLM=VABg1YQ2o2F&LHEEV%KR~n~DO-cGO){E!qUL>c(4tf+ zB&2hJ#@ti6uhN$FV>DhWUJr}J+xgc_k?(i{;UuTbwAAtlg~jvQefuk^N;~3-KpZX? zZEr^J^ww8u-(6|L)X4TYn;S{ndmbt+?E1=k{1&?gBQAE)GRKR5f*mT(UjYdG7t)v; z&v$;SX6e?jHD|SWHGT|j#ujacA0BQm11#t|4+&Dz8CpIF9K`6q;Y;PZua`~B)D z>Ly2JS5ohNtZlKT6EVbPB){Gc4}-M(@Q+w*h1OPBB1iwLkUBSvOhF7A0Vx;u82Ft` z{5>}BhkiVOOUP*xXEvo%x^eKFpNX-IjK%VEKiYINEe$U`{9~m&eA1F=1sZhEP9N6KhYH&FulK|m zrD9pzr?tmpiaeq*4Nl#1qLqq?phAlbAt^4t|d=5AWD-SrAuW;2a;{qRDyhht{yY}T1ltVtwtqP#5iu{8g zQ%{e4Jl=>6kL)T+;z{YU>nPyBcuv>d)lE5|Y+)((_HGLt` zYmVaix2Z*>%D83gNo4M}EquRR9d-Uxt_2>+skFP{Vchww-T_wXn)il4p4z^0pkZ48kLf+~i$&OT z9CQl-c%0UzC?YXM{LQG`n5HYt*)d5>*0rT{f%!aN>0l|k$S&a)_=nWO3Nuj_R?6pU zN9ohChEqRGQPPRYE|tsxWg&ZR`Sjv`Yr~C9gpMjaZgfPPXA52_d+~Wsm}6b+9lx}s zV`bj`@=@#2amYjJH;tVU{|U6szI24g_ACW#IK*6_2P;b6y?9A69u#8o31_}Vo2P*4 zvORTf>Al8QH-Pqt7Y~;vwqF#6+awMn=g`Y+!}sSOMQdS!F}yedlG89-EVC8}vG%v7 zN`H$Z<4v30SAZ*mkdUwk*;+aGCw3Qgd@URYe)OI3Uyo47srNH`#|KeSV&e0jYVh~l z39L*3GV$<%&-=<2{Vxg^PsbqcHbtiIwS>;ckt{&X56!n%d(3x*NsYi^SQqZrhb8 zo68b=R}ULxZ!JK3@-Q+KQUz8roT|ycx|aZ&n0}a8ydsAV#&$l$?~Yt*dL)fN1aXRg zMwz27!bg1MxwG^Vf&L+QxzDl2dPrE6#U_n^zX~-oFcb$k=26_sW63r*D7DV^4~Ay? zsPc1Biy$wC*~+XNDa9m%fFb`dki;G9Q$`<~fTJPMJ>9UURBspKjI?p9Wb0b?|A$TM z_$5jcmV9-+%5sWty@=s*>pfjbyEyx_K<|9brD@+v&hNyu|1v(*b*~1foR71qT<1^? z7JX)g4ne{fcfi|L*Pj-hDOnJz+l$i=E}X~%ek$}FEn10-QpGmOJv#NzirT8rfu=@Cq!ntD2G8{+Y_FIiiv&<>ohOB2!1v|Q5;Yk&+!J{D zUbz4p{pZHLpfO|{qtR$R>UiYRA-PiM1L6bKqE;)7?{jgW<2bdY#ny#hOC7lLimI4$ zek{&X{%{)jZ5D1%mvch-VJpd$F+RH`e}Emy!{?wwo`|y=Ch2SY#n6aZq<~Y9w`E}H z4(DX|=28E-c>ZW@up~2-#&dSRddi;Fk_;eP8NwjSrW)Cs% zP1{jS+@JeUW0qpS47QGvW`+vZmSnQ5jvs3OD~X>{jHKidb;66aiB&QDX%QUSpvgL2uUl1z@@Tko}hX8?bA^DAddSHdNj>}oCNsx=>+ z{p-YM$?7@DS2v$I^w`)yK#@ySejd*;SHK2rClh7bDWRzjDKCu4?N>?0a@7&0ap@$f z;miPggm`(m%AO-qH6Rqt<0*bA@Ka<)y9F23QG71Ila)ipjXOuCvElhRtJoa`ye7B8 zAQ$yS@6Al72Y0R~ydn{%mM))z!Q0(aHwZBTd9}n^AIBu)_Qb@Fpy96Us-b}fyJ5c1 zU+u2?2!!jj7|L3IkHz)cUboVr(|sh~h=hiJ(t8^0hEId%>GplE9tuWe=gE7;<`WOb z{E-AA?X6}KkA9_)G7o-|D1NIG>)O_OFz5@wV^QQO07N?g1@BXd9sVJ=>}kFPK%K^^ z9yf$DcJ2PS3fKsrsh%1fn-G>!JB$uh@j07^d z-sBVL_mJM)a=6>WYSQwW*19pdY8OGpU}$f2Dw=EB%dIWx{K1j z&^d8Eu7iNEECOkjlHWW`suGU0Vu7y=^T8ua?qwMlrV~<}6MZ6!XE^pPX7z-{9#&1~tm)fah3)B~ztNu3>Fp7NKqB+p}!i8E)XfGrPm1wgoNXLiPLxtJnBDB$=;{ zd8f9{c;GxC3m?6J^%9Sj$6fBqG%<0F^c_^+Rt2u?9g6#N>C>o)SCz!|`S<(!_X0f3 zQ0~VN`I=0~&Zz%{F%910{Dz;GF9#brEoxPjMd!tug33q*dRjV{SxU@)ASZi>OnjOb zz~MW=o4(n0yo;8R0k+XF00~{6e5m8hV3R_Cli4`2TPyUjL`@rV24Iv#(--?sQ8zeA z+LBfsY3b?7?S1vQp zE0}ShiyCg}J`xxT^jKZ3G6pe2y&u>3vb5xtWP$-5_S2iAXKBorZ9Wg~+nj|7ma6(s zGL3NS2B6T8!P{l)2L0(|Sw#WdvbuHCct~gcYc4mok1umXwxNB_vp38>UnO_402&r@ zg9pMJ5AHL(OJsXwDf;-)!g_S z#gAU^syk08gQy;nSzaZ?3Ukm{_!c*KD5_~&kZMk=7@0OdyOZ(zLxQc~j{M_(^M zz6aN>vWh~EU}ylB!huU4HSN9aQT_r~@1B7+0o0WQOZHE@1*eS_|NfT}?zCQh{|&Wo zg4JFw{@;xh2vhylt-2DxCD*zVH3cI3YJjR()f4i)8g5}XGjK)w9lR~e3#jKld6#6) zvW^40FmRuc6U%AGcGN{j3q2q+j)+=N$Uot!7yD1EbyBHUJH>E2k>ewe4m1dzNaB7V z5Ws=BRoPbNTjSKYA|1Q5)0yOngWnD-SfHhQu)P+;26B9Lf&7F%Q3n2&aF<^3ny-?x zAP7No8=<)1lWs*l*or}Zb#!_2U2gP;OO6p!;>e4Gr)r_UcfUbFcCJ7P6Oscc`~azY zNv3n9z2%7iiy8U~%iKr~K5H|}xxs0UGF#@Hq5jYt#%tdhXAi(5;4C7=E4J1sd}QMa zg!sGn7!2&hIe}NS(GmKx*m;IPS@TaR*k+fGMi9pN$;Mh-$8{Iq1Y5}S8wkQ@#5s1M zXxCVw0H}k@Y;F7inSc7}=ku@=^MxjPqa)jNVkd8w>PP~>V{S>HXsMmz*5D+zJOzEc zP`4iCaP>!tE6?q$`)5KN1o$qY;DEHZAp~AouLwD&`fX_N3ayL>T^0DRhsJ@<&`8RR zi79#|h=zh9#;_4z!b=vmlS?40cdBjQ@Dxx5&O6aXj$0$Zs#S9qWr`Od1fU9OAh18G zP8g}-D63*CN7Uv58{+~Fa7L-&GSHTYy#1zHcms&-5;Qx9Gohs4 zm9cWgVF3ERlsMes!)P~EBl4hri&?Y75vd$ z{W$(P8e$IJs`i?5(x^BN@lhnIz4|$qpZC({k*D#c!*snC_=e;i(SYH*=P>0ky-kpU zq(LrfRoTcNy?`FCC?O&;;Ov>G(ddOMu#)=lhizgm+txp8rAdmCCTMl2?Jgb2RQQQa zzM*?Ow$Kef{OTp)QMrEmNpS~~xD>ECx9D1dn_)mG?bX%u5VulSBmwlydn_dj)w|E$ zo)OBs6tsZ14}oHJ`OLL^oz(8O9#!XN_W@D{$Z3s?F~xnw~SBMY{z zv&PbwsM@yy0<=#aUyt8csLv~)AJyq~G`LPJ?o5&$`9%IQ!&#jC9sYH8hKQ!6yc;!M zMg^iYKF4|?I9q)!qUj2m4=jFoT^}WLkyRU*R-wVbhYr|2YWEUrl@l$q-301=#3QMn zxUmP{(wzIHL3%w}_K41^x6iWE5--pY5FxLXodxQLRW%G$UYU4R#S6p>cn%^i46p&3wlJA>I?|+tJR<9Ub_BA``p9!aMy4rtI?%=L2Hp2 z%)u5z137qGR$ZEkb1hU^bqF-7g_w8fF((CvVYe?usjrS{6y0{1Nq(%npCO-4F_VXa zRL+%#B+Lu+EmkMm!p_*mo~@-VY-m@{b8w7_zj_y=8>>ckhuXtaH2%9)Tjx`xFscm(tDtSYmlwvY@Y#wYx=F)45S(dz*|F(A+U552@lxLs4t<-6 z!fnmkS_}Y$wbx5kQuI>)wrxq|m)0Q}AV>3Qlr9iWzOc`Eu{ejPcZu!i?eN-}ed}tM z6}sIxhne?Jq07F$DSWB_|AO}3{0`kYkNdy*JCA*Gzeh*S{SR$a>gGpl6+jyu<}tqc z)=-@xFK>F?f5mXRN{Xo%DKUZ>r=AASP;ds?0q6K{8ktwqc}t8WH` z;jiXN2WW^CAXdtw5seQzcviC+Er-XC1V*p(G`)she1?rZloiH};-U=dTIU?j^9k6RD4 z=pw$nNoF*8432@HGK{ZOVJz`v=dsRby*n#|n*6fyW1IE8GD@qf7hw)|`vZ#Ku> zos#V*KP(v2s!))`1hQpDQ@xzan&8W0pQwZF9vH#XOts_+0lCMvRj+zauPjV{K1UV`v+r4RDOwbV>tra6kr(_4@YX)>jYdBQ;e{-G~HB zV=d_&%&5$uQ1XFRO#o*b)~CbC)W(8ysBO&q8C&cbN@JS2w;a#AWu#Fq01)-jtme;B z=+Xr7mw}(0{_pUUB$O?coWl(f(*WkH;;Cr-@D}Ij+M@aWx$!-s zbm*4Vrs!)2)kA^Yk-QGu_mpT)boSzcxogQvfN>)!q3;DS_mwiOk3=(iGP@?5XSvND z&HKDNn@FAj!9z;00rf@4I#$Eg-jnf!<2=^VGg_I#727gHJdD`&z*5YIx+$xY6fn0- zHm>jKo3z$v3u9@V@t#Y3cSoE@$qZa3dAvZT1xnkd0}N5zH|c;6vR2miX@EtLKwi41>RPJAE)s}RP-Xzv<;)0b#M<2XB??Omez+t7gzr;> z_8T5haCm$o-L1feiocg19!(j2oG8q%A>BegF{%RHc;y+nz+3(jT8(ZCNy_)OwJ4j$ zR4v4`px#pnA47UMwG*oCNsJ(^f3tlnf5kUT6Us(0NjM*CU` z%oqj`)+3^4v3eu_ydk&g!W%9LGX!+G`pnSTsPxM=b`d;ALZyLe)k*Ff6_P-X8CDWn zKx$z#^@TF>hWw~|Dl3QaX&F2r0LKM`RB(FMznp;ZK^OlwW-bw^^8iK z73iM&J}{9>G4^Z^*qR7_2pfK6W&#|MIHYxJt1sf2^jb6d_|8s0c>2XmMny+SDz&s` zLP0XF=eaXFBL!anRi?bapeJJjf%xJWI7de@cG2-w)T1R}7YqgW4wm{le^yx-Nr*Vh zWDEXhnx*a>m9{%A|A~nLYfmD18h|cbA`SYPN@$goC}TpifGfUiPK5k2=Mjb7D=0BT z=Pjw0IvG%NE@3{FfW8FdpIwXy8HYkB&nSl`!_AWfaICQJqOUYih$9rx$DZlu`*<<^ zyQrlxRPbFVp%ii$1gB{tP!a+LtoLugD(GWe(>1<;!3ub^il{yr0l1aSF~ijztL8@d zvI>TZRWxpfNkjFUjW_l}3GuJ^;0FD(hTza8*8=cQVAm8;l@%7|!Hb|z- z3XNX+rM7y^7TqV1%!*@+&wkxs;1ZiiTC65~iy&ZPB6KqkmY#l+zWM(ZBKWi~_pa`J z@X>EBzWoD_!b!fq|Mwh&AAVq-Ql z#3Gar|6j1=#}!d0&wS9s>#ZG;z=qM{r>GX%RRBt4F23xX(gYWXfR@8l9{YDnH04ckdL;|)J|fu za@z<(Y)wPtq|B!agiBu603Bg~3<%IhO_|*ZdU)UtwFMq>_8!m|8eXFQuN5&*ySqqo zU+baDSV&?ayleNG8dPn)N-#3<2KjuT-Uf#)gyzp%11oBW&)E_{EO!VQPG?5wQ`wq( z{N^)&!_USG|FGJ{m~1Z3oZF9+*iX{4muj-;3+Vv#u%))lsNvmY#sR9b)Z_$U8B>f& zF$mAUnY6IYn%TxX3TkUVrOGN*tz?RgBs$|qq8!D5e)Uy!_p-OlUX&KXnYWpb+1B|Vxc}_oT6snu{?FF$JU5GC%sFNhZCg%mS*1vC=L7Xrb0n&# z$bLy3Kf?&Y=dzB0^YS}hZrN|w7=(e>Tq@InZMCHq50J@6&mW%t!PRaJ^UOl2~&731V>YKOBq!E_f~9)7;z{+uS;s= zUjq)`JEx)J+IYeK~lW4Qb#3r_B#GVgrs0mn8n(5y6_VD0JdiW8tT$Iklnc&;OLk< zQ^}h?mR^moi=eZ)I;qWeufykfiHNHv6`C!Z5%u&)~wg{ zVQKMX^Rl)*Oop9S4a~us-}s|I{p5+pNFMKAymTLC-fgtv@aQR2Q~urE#=U)qeRAUq zPzt8oVEm)g5`uE~67@+V;pet#m~MtxdW5wZZinX`izfDW_-ET2JAfrog2uDFr0h{T zR^|oa-zfJ4aK-cDEM^h4Kb}QVoa+%Onuqw}EJsW#U2TbduD91}$wL6I+4}g9Bh)-m z!KiviSi4$w4DF=Scx+^8SgC4_JOO<0gf!-HLfVf*pg{eih?f$l2Mkm1Dc@jj^u#yc z6R+}iM<@z#HrS=9|WW(JW+YM9PRc zGHO!$SN>MKg$HiN!V+p)m4IXxv#5M{2)|V%M>szLSALgjK6wJH#@V)srGrUO9I1(| zBW6=t`}*!4#C!|b(5)X+cxNX>w0yqK4Z?N4(dAJ<_)k>MQ|QqCT-=|^J@>iy>N_l$ zo#yzc(h#Z#B!cDs)!E$cL&@O6RUBY-Ug!2Qz&ms1+1w1x-MHD3aLJ+qA$od?0wxJ4 zZn-%@7?)5!;CN(F&3CN;lm>GNm#*62n&R$KR)Vf`1|CR-BqyT)`}16OUxc0=GMno^w*}S3=j%CjTlvYAhh9 z@lY*2dSCGoNDglgP%Ad+a^l zSGbdepUGLX^J(fZK!V+|pq?3Q)S~kzngu?8dggUBln<*Txd=X7OpfVN1%=peyu7<$ z5L6|-U;Fi_KRD949wn?azMT~TwhVdkdF5G;E26%a8C`*jTqh~%Qi~<|9KYgy3Rr6% zRO7^8z6^XY;Z+Bixl71DWno5~!2qXHQ2iF_h-Q(3sig!hLe%pv&2GmX<|jC6m9yVA zVo?YI*>&>?i~E&_pw_s0)*53OVY8vTwZmMxt@>@eBT!aD;h!k zJ|?%~AUMx>!e5n56$KHX_X@_*(8MV#t#m5|swE-Hji|7|(zq4Z!k3!XiBf#7=(^El z5l&!&YbhE_ArOZ_%*mEtwHkg5BgXk{X*jJH5BG#vxcOe$ zBL60tElLU0UqFG2dEnwBY!aj?Z-%5ep-EUoEXwHZ5t$%0W-x{)eulAV5 z*b-;m{NmEW3ng?gS)R@q?>)P4Qb7JR?Pu!N*{om+PVZ}vE z79dd0g3{79j&Yv0-7R!aS@z`No*Z9kL8z}<@X=;P%3}@=pW=H|)egn8VrDJw18ii> zGOFGk)&Zb0DAuLmiPHr?u{!GU+v-p5*J{D*Uod>h(p}d0d7pf{o$<`$1o~*W(z!Ib z98G+4zD~VHs`ygQ!vT3c=s)&4w2pKpZG<5^gZ#R^lOoXkQ{Vg5ztA_y_DcZgA479> z`Ni%)iorGKVJa_^fu6$ki#dJ-`{hg;?5T9gf3h+i8?Q2tt`xkM zpYKQfiEl1407g~!>*-$mpi*xB7qL^~dteYGwnHpwHFTCssvSuBAwtAypFPWdEv_xi z@ywmev~*&L)wg%F5-b{SqQ!|6M?2_)E8?5?qPWUkPB9K0qfj~EdJ;5akD5(5`5{+b z_MWQNP}>3TH0{rcX1!$a@ved~tinMy!<&_k6-VUhtF5{6V(muz4v(;3@H_(KS8Ae;epxO-|mp*+8eaO*&*os`@i`9=`rpG6+^JaT81m6W|F>Uw?#Nx1+`|)+01?3%S_w%zzI_G+s6S1pY#&yGIRT zS#iR8$2k~wL}pJUE-Av2q7;$I?l@*4*_R%3=EawWEwliU%9NP)F!3Q@@AKYW6l50D z!Cbb~r|63N9MZ$~RSK7!`X5y9XZuO8_V2zF$q*tB1`!>f_~KwbG^at9;uK1m($kV* zg`Bmbc}*liO`pJ-f#q6r9C52 zw)UOG%k5>g%VV8#mu!&&yGQA;K^Z))&Zzw=x5D*u>hR2>rzZ`>>#Xa?g8`wwU3*X5 zFo(u{rlCq@^$fSy?2faP*H0!?x))N1z99{!`~M@X6uZ6yC z$$R}G%=Hja&TpwVPY(J!cyfLe=L`-$8Srk!i=Bw4Tn%*M7^8eiqv`PAzE_7nK;&)j zOJgcR{6{ z(z{!Xj|{)vo{k(#k%Zl%Oel!9iOFz>v|{+4;UF>Wq%ZxC?rz7LzdYt33%oUwi2Tf% zG@t%-MAH-ZY!6dLvaiD{14iFF0|CxeuIL!4xj?3D6-HMSo9p&7FLRw@>pDknw4dD; zQ#BJ~yNAr#_SCtSv&Zo`pYcv32XfJvk=g z%PQx7b^bGsTI#tcZFjkOxQ-D^ScGhLnX%_!!WTXoU>Uy-Gi(z&d!<2Ekw!9Y_S?5K zpvU}jx}}-fd_+9)&c)x<9g4uTGrB|>z#|@i5+*!I=g6|2m1@D!ZWs;IYx%NO zg_B_KFwGZk8XO*;XwDZtB1-HxDiI*lkNNT;LfPxZ=1hoKsh{t@%G+3dK zaiM(j0#a8#hZWaB-P*y~-+GOz4DD)L^D`Yg@?Jq8j;@=3E^$euRTn*q{>2o3>SIIW ze@d1(n3^lh^sx?$V|kiz18eV`v<9wFS#eZn!rGu*Y;9nMcXwk@R2o;N^rOuH%EsH7 z8t4-A{)-*-LAS^Ri?XDiKh zCf5vqnf_A(uRX|MU7~^BG-1l6@8?(8~?v>J&w;#1!yGUdkn0hdm5K}m}(JzCuU9M zU4JB`heNI?RiB#tR2sSQi(1)0oU4TSwN(Yi#fUIS37mAOs31X{J2^zU)(grS=rfQy z&eFEugv00;Dp+6(w2`}f$&2lye9`EefX)c1$3g8d`hm|cy|>bScD>feoev5)!Oj~V zrXx1c4wcO4DzfV~aE_N33usYuO;6&wQSJz!B|5adYa>?F&(le$i2vSs@N)Z&jTf`6 zp~cm6(j8uMuL!8+F-;S+dI(P%B@5_gO|zxCY&rW8tS-%CD@x`a4ApMO(_+@O7Ww|N z1NfE2smuDs*6_lao11C%BScw>ODegg)aJ2K9@6M;2I{>^ABj;tZZ(44MAeRRyF8HF z$7uk6%%THX0+wqPRKu2`N0>0KxhY2Y@Ldg1olUzS82{`M*~LrcGD^FWY0w|+1?R!-ZO_?c+@;Mx7C^~mn?(P>$@9XGFcwCzzaaft=?{3LZkh2-_o=Mj_haB#H4_? zlG(Xcf^a36X?`zlysE{}Z4Tm)Up|~GBKVnypO&5Y?fGrp-xDhsBu&`Yx^zAgE#3G= zw6#isU9zc5*m^^;*xKz(7`?Srb*g%Vn&4^NB)G$b5jG(W|? zH1kAva`0K7ZX%|f@p0Xo%A4&cEa=FQE}NZ-lchiFB?PQ`mZiXOap2i_$#$%I&Sh=P zwR`k5hs<*Xlw$XyQ#%`9#-~_ERN7nU2LtWW8Z>{61gpylZ{tFWFAP5vZYv~5S&=d-frVViUdT>-MK2uB=UxaKyNj zW*=RNbwUE)+=iz^IuWhBL%xS@WfVs?DM@zX%jP8871KIL4ik!XxLVhbcbHW3L${v3 zW?1NbO*LXd`0V{gTUqP;-#)B~E0iA@E_+V}2b^~9Z>4h-%cxJO*Pzn!R!p&ZcVSNd z0Z)sf-l;T#D}}1I*@p-1oLWV)+1N-N5_kP%`${5f#2@t6z#L$m5YT}ixa4(sR*4p; zqNn+}H8~2fC6+?V8Bs$s)>2OpQgJE`U@AmdJc{~~pyv`M3x7}KOf}1Kwws~{twAZW zbsdrlw{$p%mk;0HFqmd49VRrWZN1S+9Xiap4T?yz4_y#pdi%mDwC1Vc^ZW!_>t41h zL1TLBzrUuw=Kn?@pn+I^U1{RP8TSY9Zv0q}ZuG{bUf_+nbg@tY; zS^u{Gw&GoOzzFI9H)INnBj5gZuvk#0Ul=)aqjMNm!EiXEbfSdvj5~9Qr>ho1at>@C z4BSks@onF(og9jS;#|}KwwdDWsc(UKLbIU5=|u_ZCp}N)Et~GHJ-%=p9r*cvbvf^0 z#*@LjPk9OS>M2@@FVt*Se->Pgk6m^pCCKm(zyCqx{g&MHiNs%he%(D`;qF(_NX0>w zx!M;z5bO~}^{Jl4msCHw{e#AU?&8#7H@V}T?85T0n(Zj{IEQz}_gofGvOJ)BuN}*R z02IL7gRHC#|3~yGr3DXeme<@ZkBzS$H#t7mpl0`RO(?rh9nPu;EUZu5t@fC%=Ea+i z+|~0awNlleHhYknO5#_1%6;`r&tr!cJX$(~lMXhCd;?B^%iC>kCsU=IZEG!ebuIq7 ziZXe3!o<0WI41f4-e^xlbjYpriDPiNXa8t%s((DDS_tM+XAJ7!zxy^p=e+$>17wG) z86UU{`YZ1-3WopKuE$WdEGxIu6>PTg)fw&ZuGX0GC0w^Ln7YQA7c3`xxCa*i?`!tHSJldDwbv{>Oj=mB>UztI|*maBTSd=K_#U*x@v>MxRvjcN9UyRc9){~ zOF)3rr9Kdg!o2@p8-J3+`J?r-Qy1rAy(Mva+m2m0jIXmfe{V&(2eQSvowtyhV?*EvIyg|nIAzVyq( zH?r9pegtAUYLREcji=+66_zFikDLpDe1D-jE;y89rB9nIb^qI+YQg2g3;SIX1RbUl zW={Peu_8iR3`>G$650@Bw+a~32{`yU2KGr5=Dx+C{@;Btg&C+gF zU}X*D;1pia!+#Ju?taw9u_yPBCU0^1y*#1A3*xg%Z`dw#PKhXBmdae}Ae7wvcHTBy z{CL-I3AK3fFyPSuyBsORetE0-(#(unb@F!cm0RM7$D7&ru;Y4r4q)Srj}93ad55Y9 zr?nZhjO4|;$8tStVmbD9-qMJg`0dMnRlvDiSv@{kQh_Rn(c$46H_*MCl!9*{tC;>m zUL(L%fWFjclrbScRI()%JW0(+@Z+qZY2_1z77gOT`oq zE57=~ku2B#>jRWLFIjikdBvD4y3{P~t`#L0ev#B^SRDIp7h&{sl$WsW@mNb~nJLL3 zN6^89X1IDLXVSK93iXWbh#(WUj`7O8+t)TxEk>MzwRLyzB33jMS|=y4P^A(Qd@Ca? zpefQ4+Z`d58&W5@~2me-DWU_Vr;Ty7|Y$XCV03Ew-UKE%jNtK8m4b(SZwl#{6?u=_yuG( z8GXN6@vm<@%|0kL`W7EGwU?Mx1|}C?zm3SS>G=~-^*Cf%bU0BoZ1!XC=QH87&xURk zQR)kRW<$x*QI(6BJ=e__&Gf(QhM7NpU4>n4oK_32dcv#V(2;?ro#hK!Rl;;yn;l4u z{n9yos{hzY$?`=;c;>sxOnZJ;?#d8N6kKm@S&dU_`s6e$6*_bG|u0xWlqp+C)+ID;otj5w^M>1*v+b@B_iK4-h1?~*?=UkK5<9KsLL1MeS5QV z|H>+GN5<#@F?^n>@vx+xI}`zZ4>#Gc71t%PF;6KoRhBx+sgRcqGNOLC{Jkg5T~Hf+ zQ@-M^fkogqsI>lT<$zu>PX*W2QHt}Gfwn;{NjQ&=FJmk*_W9Wk!G#4!sRFbP52QF3fNM$( zwbH&^eG5BYOhD*&uGXEGzKu9fcoY(;_&8{EN7CCi&jYil!agI+FSG((*-8~mdxBhIsQM(u2*D_V8EuW^=;XfZ}!`Iuj zX&@$d#iDtO?4a)6e@4w?%xfY_bz3?odW(apV^=+HxoDl{!{`_pG$(Jz@v!8LmnW{j zjl2hk1ajWB9#*nNntA``(>BY>0e7N)AeQ9F){u{Ha>LuV-+!zvRhgX-cd4On|r^U+)iwxV`V| zoAQ!p5lrj?bf_L&L{hiW63Ui*?5r(dxIHg;)Y5p|>wIb8 z!UR5#-v`aep|78b_3qCS>f6K`1cEX zDJ+*V1f8qY(zl-LL7a^bOii}rlSidt5BHkQp4!m}*x&O%Hr{_jS02W_TuyxM7B%WM zq~w-!KHAVz*j(EyZ2A55TOXZ#Tm4esZR*BSxKq%|n%RFNJhlc#a~U*d z9@{X+;*;&-(tZ4}-VXXi$41hB|1Q7HBACMb*s6E-5)H8UYnYhy}@cg^%%59e)~glYMCcvqm~k z%050SVgb#xqtgL(081r^zW}(l>e>}cAuC(H&(rj54kb4hl)9Fqd>}fuybPu3aq-G)5RrXJ$W?BR??!<_`)gK`%y+2<-RHoLNmNKv|H~`7 z=)iCH+Fi5OYdO+KIrK(c%0d-6Zf@v%YL}l7%~YIw!{1(&*qvN_P>SZx*1lfmn}cBe zm%d40lJcmFb!Trbk5D=vN3$eg?47V)W@&IAg_=Xu^FJ}E?FE}IEr zw{5Q4iP%DvUhK{-}-^_+R#Fcd^?f0V{NDZoFUXee~?7UefxH-(39^! zGeXsbFMq<*s=KLNWEorQam~$Ud>!3bF-uFtM&6eesCbUezZCJvZhHl-LEjXudE<({ z`$06IG%5P5BnzA_@;bfk`SK)TmL)%;&jF0vsXN_)U*PiT7#Do;{+tMZ=m^v#!}av@ zW=zB!e*#&xo6X^qnZc!PQVlFhKTm1jj&=RpJtMDJHZj7$tENi|A`##G(EjVT0~fCh zTn&0=%3;qS(NX=b6Q@K*8fTF+|FrFDq30gr?WOqz7}=k=om!La{~6WjNyVu;TfjAs zP=Hu6?%sIoWOq*%>!1;vFKg?-q4XQLrGT5kRu_?{J3?=+o<2FcH)-RXpJIVT6{FoF z0FCS99gyf*>to^JzTERwgSrmgyQ>hF>eNot{3g3bp;~sqa*C?aI}`h?BfuzRT-Erg z1UwD)>u>qos+gn!7hV*swLs+UN67obdFE212&nO5YT7}^Y+P4rpyk|MG4e#V=6mBE z14Ouz5){y_EfX8hr#Tzo1w%@z+0Fu0okn#nSz~o(r}+xrt}X_*G+Zw8Ox|xryz@T& zBIBKSuZdcvjF)ZTsqf-cb#40lrS?b5MsCW5p00Wrs=8e8V_$_ZA@FC-3Le8UUc5-- zUP0X@PRGI{uqObBenn(2P%_I6RCI<7T1S6P*i<~)-PvQilUNy^a%Y(Lq`X>-bZVve(ThmJ9$=k?Rvl!o9j zu^d$NEaWFbDTiYRXQG80Ohuvm7~0B|_gP+Ft;3g4`mA={yzeom2=Nt>oOcqsg?rL` zJEhJ3Yd1ViFjR~|?omOI{(0QNSmcYZ)jo349dufs-{{|aNi(j@DQ6I6U=wGzK(lF` zR#wGG_@sbB!OQvin1mZa;8A|f=6i_!iTBEAG*To%2luE&pcm#`R3346)#5?$)xBQu zH32rtGxf0MhJ*E}UP^IMAiqk8+w3HFA6l~RFr8)C7vJ;0jw4mO*_!UTI{y84guSSwjxq*dxZksvSl)J98ttRe zEa!_8n@OYbaCg5JCW{jV+c<<3i`L(5b}rq!1}aZREdMcn0;+KAb&FOK-~8n>p~+() zzq=>yOA|#hbN3K^?sVYT<=b{NrQGNbwYFF1_CN9|ReR?(13F^^z|{v{`nEBXt9 z(X9b-8+=Vi7K};J;hU+7idf!{FZYZK^4Cq}us|1}g{)-l=Q~}DD(g1?$eEi}{_^bYdG9ks3#=W$DM%xEyTH5}2%=no@=h6y?h2AxPpP7gGp1bR$ zuv6CO!vOw}g3ry5^iIC-N`zFuaj{l1?lNRw_X^RmWqX}1WKMAN@J zc;1=j@Za^l$IS8?r^jE@w#PNlAuC_~EGA(F5tHMD1yJaZW|@bkBHpYn$AiTWUr+uD zW8|h&M~Iy4Zf#Fpz^#9GJZIR_elX*Czu@D0(8WjmK7njgUhk9~nH+U_w>~$+lDms3 zi}{`r?7=*y#R?$@_v~*S9t`DIM5yJuUg3@RMHqJ0=BCW@0X(5&_p(U^;AfVbbX@6M z(=z9WrRiq}JB)%48WmnEI#c}Ucp8{Bx*HbM{wm0!wW(HEjWiPBi`Vz4U!HN?Bq|!S z*(*hQ^a<8-j%_BTv)+_FLjmmg3%ER&9xp>*#Jk%!p36gOS0|1R*!}9%dr)c{s47{v zT<0TIxuFIzD8>gfhPd_G1=lp(yvXxGZs*n4fLv7!XEt$|hFeBG)iHht4QQfCr}?YsD6VSQj;>nMx-A6x5@?p; zsC)`_2L9yw(6y}(<|eNynaTn5_{L#qZhXSp_s13n41u1)#dC4&TzxCxqqa(bFPkTK9}Z&18BRIc!mMvYx(*^ zD(RcRiG3xNWsq}<$ziPFDNz8%pkz=iY!HCsh&A3a!(!<24paq@T^308GJ$d}t*oY6 zm4FpgmP0p*_=&H)PaO^0hi|9KM>$GsP_ZK9--|BOoh7X28xZS;33`=d?6K;#YJuo zGF*!O%I8yuAoH6E8aBJlEyIv8S)yz#f84EwX=G)r!-bsBDV{A^@Spi(!+w2V@^d*} zmZl{ETh+c_#q7$dbb^SE!9n92eRSxHdqj=CzK%<|OiMFsq^YVkcUA!_^-bf-5FxYX z`}2NCY4-8#NmajE2y$1A|SU{5yY>ll)E16pLZ{Gs;5= zIMvs?76=l^|N7~6a(hM~`*JP!_~<52>hYW%uMhhu22wK2WUXnnXAI2Q0#veg7Kj5c ziwoq$guDGR;HFmjTA3iXdvVZ8bWWGFzh&5PQ>}5;-pKyFG>?fa@!B(V6^0u97gEuW z<^|OCm1~4pdEpDrhOPA*-`H9R{8VL2VUYT>R|Qmyq>HAhzh52sBCp>L1rBItJWvWW z7N()GT6$vyqyo4blbUN-Qt+XY;dh@;?s&$ENt`vO)U-pH1FRXY+SeYmzGLp?ggkMp zSst1O4!;Odb1nTxSpvj9m8i;S3yYECP`G7y(&Q3QwsYV$6|UqP2`~?;dHiFlX7lS? zSd`=yIlRMTOiD7!wa!-zsF`d(6aFM_sQmXM&3~wR1;4lf$jWsa>_vu+TKv3!?|?9R zA0b`+QOq-5wZ zax|BEBlFViR=+`Grt5OHyxN|czZVHQcB>bGUFahKe18E#mdAi|XI;?q>p_)GL*|dw zVPO+(KfBk-Pa<~D`*nd@dc(kyCfX!6GlU}*%2!|~O8x=c;dJ${nvnNV!*j{|b0qx( zJF)8UXo1hUX2_FkYxrrXQ@nH6e(K<87cGgwP@8O)^#nr(3levWGs}grtZh`jN)U&0_XvbcsMaCO~ z_-Q=;%J+=7v?SMabP_TvJ^_g+Uw|K9VWI=ntR?Id+=ME5hwqFN@|iFF)9>cYiFR<7 zI@D=86(`PeRSnrKJ2UZ*vZPiSV{qpMgq~z!OPg=M1Sf$MoP&2~!kL1mA#L8G!Sx!{ zaPKpZxj3gY;qvtJEh5T~Nd(7eY1>01pz#jE@g!Fl*m%R-h+|ksMw0m+&m|m9RTn9t z$A|M;DFV5XlmuBXEmTkFyOt4@D6DwUyxs{+OULolus*z>ppb!ho>a4qx&tcfv7%js z^~|Sr@^~9)@LK;Z5U=68k=f}oYcQ~1Z5;2gTBd>dr0Y@K$W=vm)k&2>$cj`@s$RP{ z`uV5ZdPTWr6&tI{-z40g;=5sXRBqkrLJaJrPJX+M6&MVG46&c1h6jcP+4xUQ8srTk zg53m&KPE0UuT^En$7R|11U19uE-t2`t!{C04lUZqZcoBbU)Az>pG7BnmCk0j^;zmY zaGdAZZ+beeqj9%WJUv~DIg?jo`e}rQck*msNl65KNG8}VG?j&|p%`*~xWv{0)|sn{ z1)J<{2KI8j$AqePs5RIM{m-q0;}lRr_Q=|ryft%!C$D54|7`HvMFHO6u)=RMx;X>| zm`)OQ=k8~1vbhVwvWEd6z5`jTOl+I%MMt&<77ip8z=n?BZD8WEO!S6?opTn zn}Ezxq~O5uoab|WN7`J@@Ij4K|DTPw8|ZPK%ie& zYDMZcFsEvq00X_xN7%j313F!8^~S21hTr*7s&+jEv;0`gmluYgJLdfd`JzGznylye zJVNyB#E3UBH-4%#PxZKpb2-|_hz{Varw^bPC%{A^}Dzxlqa+86z!`de*p zlXdP7Vgtx$DEG2gQ)H`hEPb^0eyB#HX3vWRM5e8;9~gjnepH$LESyHbmuXLyW&!eAKOFnZ z8g6%^Jg;^pXks3aJvU}Rg~Z*%qP77G%SnnQ(!*a?Bw)5M=h7LPwP&2pwCg`Tbw?(3 z#*9T$JLe={1IA#9lR3YC6+K0H3e>htp)ZD4NemXX8|lVhFV z)pMbywG$dA4|h82^KJj(QM{KWZg`@V<;>XLOki$8pIt9bNfa?U!}%Kq`TQ@09T#X} zPQG>Xb58O941!`;+X6i#C)q6wPy^f$b%MyE5`EuP8>ISDySW(>!|(B=7<9R{TGhtC zWu?Vykh6#XrfcTB#ZEz=Mt8cQeRKfw+Qh$eX)*pml{x7Xqu6>4yX0GohAlNSE@ZNU zM@n0isX4`Z-Gq4nwVi-Nj3eSuhT`U|c+m{mZ@1Ro?zCTks5UeC~=!1%0o}x zJiv6nH`8;gpAzxV$XyXC;P|q^CsSUO?^(@ry>kkVu@f+4ZBr$J+NZh65bd{5@V8#3 z)c_x=QU8HCvqsYpFu*Y{{WiB&okNwcT+12;en1qAVuF`Ei+s z2M1ZZTb|>j+)1KvRota`$a>uO*-p&M5&A@%DsNsoNiOp5ivoF+#EK!$;|ylqc|Q>d zsqB^%!2sPHFkji~RNd)Y*1JQ+)D&-2%oD#~j`gd?9b5r(HajOFpt(p~XtjuHjm=D) zT>BGjXI}64Hx81lP#TOADPe<5h82U<8SzUJE++D)q12Z0a));u@@JY5`B9^Gw&(Tm zqFK%bPIVUJf3KsHvY79(lfiDEfvS?N&irb;q~944&~b3IJX~FUy&EQ23^6WX=8oHc zp=FaB_Y_>Qf9q?)z!@=?HIr4U-^FMTFgfZ&FRRU*)DH=GpiICf1S$~)#rdMS*=5h! z6Z^Q`w-Dg`l4ok!!_*EFQZ4&dwonPmB`TEOTN9B!E?~hWSe)bJFvQuPSZz}Q`*hcV z_upC@z;`BJfZ8W<@mmhe%9(Y!P)0}-^Cj3E8dd<#v@fnJ3b`D83Msbg9Hx}lSN2~r z06X7#4e~=Ss~`8$#I1X`ITi)2R9(#I!5xC!1ILJrk>U^ieD#$Ss!3KYv?5nAW^)QY zN~Q;o_2h&!5{ou!$qm(?RD=Z>+bJ>h!=ur|ew<*Jz%LsJQk(yDHOOMfNQT0jP_rpG zKo$7W1j*b1R*Kvklg)>)P5$axO6~mK_O8e1qKgX5VjwEea#`k~vf}ID6uyU&K-RdL}S= z9C$nJ=Yzvnk_RmFbZ!YkDUz<>r04#|`dYg*aB^WWLI4TNw^`~kKRVYq8-sv#tNq&) ze1!|~Tyn@994HKo=K@v5zju%vu%iFH!$;tvCBRUfe;XoUQ^$9tQwwufm@L*=_rOa{ MN$XjKf@R460cRZB5&!@I literal 135197 zcmYIwby$>L_ch&}NUMnl8V#lr!95?Xfd z2K6!gqLcAitnk-sIU zrhZ9olf`J?I6q?#yYlkV^IKl(M38_$&7Pt=+0)?!0~ELeOhasYG7s>-_>3XqH8f}R zmB(7g2Cgo=CyK{P*YH)n#;N48dWMD@tOPsDIcA=Qm&OZbqAAMJXL=$;itAuY!a*cQh#z z!eJ3eiX@r6gnSbB_A<8mt|K$_+ftR594obG`qAV2&rVzt-Vgo53@IChx4qeqzZR;p z2(rF3>%nWWWfgR!n6>&8RX~NUegC0ylhYFf-nW=27mt&WuV((dmR3EdTaYyLTBE!u zr5(-xeKjkw<1%5qdL(9KUR&Erf4Q>W%I8~`W9%=bo9HZ)1OKil(Rv0Eyxc)R{Tp6w zqx<@46{e(kPjgj`2^R}XY;qr4%>7CW5-R=R3GebGNFY>bL1@DJ5zC!UNuhFbbX@;E zk(}Mb>obp%iU=8oP>#m3avs9X*49Ju$S9?{f472FP2!O0D^sk7_0V7$CcoE1ZrFo6 z_vk3r$Nzms_t0p~2iY6;i|H6ljq%VSPSSA>mPA&nH-Aq=8MB(ZCZg7a01FN`Pivlp z9e;{q#r*fZnhUhB+?oNpK3^WPU@w{wg~(4z7Wsb;|DGC$(+VB3HDNg5(lfNwBF|79 zIFsxQOb{Wc$shVx{uJnF|9iZ- zgBzC??xR4h{+>`Bew*-szygNsZvhThz10j?R}%sJUQdkpS=xlOb$WLy`FSp_VxkHp z{_o9k0SV`at-p%Vr1(DKI)^s-oO$q#)!%YKPIj@v{l1&_SG^xjIc(vpic;z+;i$Yn zG9>~o-jL6D?@q;_@HT#@sAS~AIqh!3(dclVPQBK-bWqEwwvVgH$!V@3K^r#mA@#)|p`;kMefMH)FgRzs2dJ(wgvE^JKib z(!C7gSf&2IovFG(=Cf0D5^y0(%c|~Xw}d29ero>eyIrbn#J2y@XT)b>!@S#MNC`J% z=)VOMBk*mAYI2jKenet${x1}{(fqf@-}nl;f{+)v^QQG_59|}M_YIi{Yp5DR#x8zI zus3ZfTR%~(5E;cCj>oR}?t{DKzQ0^xYSXgHz3cdxrMB?jsQl!2&8T-GulDBgOJ9$V zn30uKPnPBzg2x>5v<$a3k8Q3}W}2U5jTqwdjf4#CT;9PhjgVLODd5I?U^H%@PM%KS zzhzBtE+U8g=S+wqN!XnjD>HiU0)MBEGF8?THHn`=QWk6S9}t|&*y;Pv!rggFfZeyM z``|#l2s7k(TUJ^U3LXs}pZUrAr+@3!u~CZ+!3Rg${IE}gZUiOwkr-8w77z)q)Zhur zJG1Z75f~;ryxduGgNU6@mfiSSCyt3r8jyek zshbX>1NstnUquj}8gQ7#cU%|B=%`iBO=O>LzRIyzA zhrm@yARS-Vdm7QE3y0u3+Zz!F%D-1br~Vt2tU5Zzlu8$ZZ5&dMeS3?HQ&v{u-QWE5 zSm}5)vpr212u{Y^7p=0iwRuLx`1!82^TD5Ms4r@Y{u%REs>Jc|my4CfpQ5JY|6R2* z8(Hwr-O3dQLG&;tMzeXSFiUd{-Yo(?m^d> zG(Kv;F>=~kSjnwmXdnV`_(tP{bSDNG`ky-nx@o=l>yIkn{5Sd%yNisGNB$^(!}S0| z;jlrQZfF>HH~C0h0CM}oQ{L!N`qO!l1smdz^z5us0)0 zZ(<9nrXO!EmA^ZGwJx+S9HQ7&RmYsr_AfH{Asaai&yweNw_AVK9f$eYuUBU+S1l$Y z#}Dxc<;}wlvwgys_nhCY&Rm98w6a-^WatwMeNnAwV8Jn%on*iCPHAgzWSee#DTvx( znQ%OiY|&NmBm%}8(H=;3bne54+U0Js7wLli<_G2bv>6t&w}Hnumph+e-drQxxuX-=7Xls zMQ;Q09J8}_fBGQhzhsN^WEkXReBwk68z#&m&`iN27`7}Fl0Vb`0IMJi;miuCeeBC-L~Mui zOHi5wj>2j5UE2?OG3c-MZYg_gjF~r{FcZDz#n)gKj_L;0)C(@2ry${s=uu@EYbggynW z|6z%p(gq@HIWY|AR?pl^{teZEDJsU&!(a6^K3?D7p_4A!Z@dIf+vM}POQht--v`|;N zb1pCU{q24vcDdQ5V*hKNo`=7FEBxaHqP=TWwx^rNT)Gu>-8ye|F+lvtGG$HvbEGfF zI*N^fyb#uFL)Ud~d>i}wmh#-ShCBwdtq1PJ|6RoL5A`d#^<|9iRS)D2h96UGfuCQ? zk;8*uPYzU)sAkL2fHEEMWR5hwzw8FUH;8erM3QM)c{x@!9bHI=j_2&I42LC(MWpCh z437Iez~$ggny9A7Ez5mIRyj7`%?6^t&V1CmpSbC;g=HeGo+109yH2Td{l%|F#%s8* zGw^|b)3~y1c~f^1qW4zwpEqE76De9F+NuYbw3*hl#sIn>{9E zaCwx{OUfdoJF&Th`)&_X#=}!a;azrLa%f=|F;T2BiTN~N0)v#-DF%UDDMZH0jLAdg zkn+ICoOi^C;*Ohow$}P&Be|aml!9s6{s6}#2GJ@%8GTeCjt3SYEnIa#2BCkO)dDXn&n?ea&`IBwQ__g%Yg;|xpUWm(xu?{DP%tEXZVK6mKG zD?6^go=D$w_z}qky=2s-MyNO(2NNZ;~xvk7FG)-n=eDC6xAb5`vl?ci!LYXE1+-RfqhcGXr zWx;&C)X5X{^y;ZiGI7J@6VCU4&HEO7-m@qqV==jMkd%<5jQctZ#v0f%C>p+a%*~&c z?CJpP5%RqLR0cQASP3g1i@<-pj_;qUPgT$w$T5NAK*fFz)d9!xJDxJ5@z{|wQb zYoG^M@nrs+xA^+sX2|LTRJNDU4f^slrizSpnJzAxfbey|Ng5BX$JN)(R$^hStWju0 z1mak2z*`bb&l&e@W|@Phd|~76#bhEc31TWp4O<*41+IG4Xfq#tCMUnoW16~XsCe)z zSB|CMR}B5=fxd(vY&ULNMyAKRed-xK&xD=sTd#`}+BVbk^H19!mLDWj^l<+m_H=CjGHaFQ` z{+7wzvhj*5jPifmGehWZex_MMaICP>hwu6JWMmHxL!?=jp2l}N(ptXD#4bJ$zhaK5 zVpnNTLH?>dHRy^eXcgmvhl|n3*$trH<$%!RcgN}}GL=YDA>uJ+o0_`<)av_q>*akf zGiXjt^Oas)yr;k3a1`|xMS0?i28kL4#N7mb610A8O$F>pdDBPIBDs8b!?Z@KPbz!I z(BXZc`jsv&#ujV`7cz*9+s(a@V+{Z{oDu<11X;Lu%mpy=jq|dFu7^BCa_cTZk)ZRt&+zSiL+C6my@=$46 zgraHWIH5(*o(!6lfrZy7BKy5Q*Il50Wvq-8*=pS7AwaS0Y-DrPYk{S=*+PlB{F03Y zM)asU?tan2RvD1CErKST7eGk7#C^Te9F^vdlD(n+6fetVi6t}*cXZ%C4Z948C<7!su`#7t*xH3&IE8( zu8=AdX8!cm%L4TjhhQ++Z_j#U&}jCuRE?qVaCH*(^uByxGnSUXZUdzqpqS&MAy?I* zZ2Bn)Zp(roTdzBdvkNg<_|fa|O><1n#cpF`&q8fC_OH|z56)pqN2lU&F3R6?`gF97KwjK=IgEs1U_gOXgtcn@2!NcH9h5vxJLIt(UN=nT4P|)#9>Ehq-5dK#)sZr)ZKh5 z^>;`}8yIT{X?4 z32#mOBgtHy`X3c)a;pdpX9F_f>{we_K=3IO`{0bL)&HtJWvTjQK`o~wK|B}}xLQla zAn}&t=eFhaJc&hrlhDh^xbB?ghKSG6-jrHgB3x}atrtEiozHX2)u`;}S#Lp<2`F&` z^z++?W#x|%u;wIe$+pJ&y5OzN?)mh?AyYc%jYu;no7XklrH~~Go=|Nl78>Qv6&$M* zX!UZt0&1-WFQ@H=ADC3B{-D1Hr3GJlSWsqS+(wu>I%F<2<=?OXJ;S1W`>Jx~V)o*VdR(kLa7{ zFmp%?rD>WltKQwQfgj18&8w%U(-3to&)mNz%EG)`p z6&O+%3knYr^US`|v)JH%E9p2)Y{$L0_QEc%DUp8@;G~r zEVt8{q}zz7hUy#Q-Q936xRwh2pjGy`-*nb*-^2L5!ULw&*YFGHogp~muo5h@9sMt< zg!z|qxZNSWHGz@Xdb&M`k+&3Fi0Gzv9Uzi9gEeO6GYI%lMubj8yFNQjDQX%-HB^iZ z@S*g|vzz3Il1h@|j-$C}Xz3d=<0L7q_wh;g#$TTG*$`Jgj2&&n)b5)tnsXoq?dRZI z;|g|d*<|?%21B_Hck7_->Au&&XAGhqemadpMN19zPU*QtlZkDA<3G2|9`p-!u-Yc% zwQp?Z<)OZ71*HS-#1`y(M#BVIm4#P^bLZ2xo8#kug77j0euT=2$HZIJRLm17KDLBo zY57ivst=1mw|LwfeFuW8_-is01U`8WZYeAk*AaN;XeR>1id{FKT$|=;qJP_ZFDV#H zqXRc)7JGSXt&zsI^Z5Bw+x`7Zx%V&c@gkP!2P`QgVu4h>Z>oaN{rNlCjRYxtKZv@* z98otr? zb%%;}67E?jk=p*QIOtc!0hpeBjMbULyrUN??kn_8B!@KJTDE`YEP!O&{^gV8SJAWI z8AGJ}#Ejh9)Uf9pm+Q2QaA&CctQkiIKN+)fY*<1VlK|YXo1x9PPG|M5*0^`UZKamz zU4nLA?H~&a(|lWhkrB5MWdIUDF`pT2C2qY5SqS0Nqw8_qQ$G=50}?{5 zq$dxUncy4{Fe_k8K5j~aN5|Z7{#-7iZHgQEZaJtIo;7zjhOdVaXKMX*mTGG{-@ZFx&zTQ?@ie?=0X!SvI z)G#b1;Nj~Wb(gEcnN&4a=)LMg!EQwjq@0fCA9W<(S48;>{M73Es!l;oJLfR^V=o%$ z)@eZg+6$Vm4<|95I%@*0q-wQw(K9?5Y0aRNt}RM(RTd%T=*E>3PKeO$uy?iEdRXAQ zcMf$i40~H8ULnR`HvfcbuiExYdBaQPsxg?_sOKA1PdMdR=>nxYE*}B#tDI|eFd*YJVaQRpbt6@x*vD0f}H15WobAhS`tqD$i8zrBU8@P7%@_=66!HdqHdNjx3X2MWqut zKW2k&8PAv;yo2kz=9@$Bx}Lmbr%muRY(u}jb=n3!nQhdB4BC_^rm^zf1NrxsHzc6v zSJ2DtVaKE6ikG`$va7S_-?wv59rRDag~EuixVu+prrB{Z`a^kqTKOwdW5xHTIHY!? zQ!yjs)yNE5p}s?c+MaADd$y2dbmKfwpab8Iu49OzX>(4hcL&{-(G^pmOXtCo%5_IQ zp2-#eGb`yT!gpE3wAq^gVJKMfL_|t=;lp}WUogy2c0GT417Q`rKfFmaVkW-@7)**b za@g!jsy)NMp(j0S(^7VK^H&~qgK~aCuRLzNRdof=$H}?~=6ZdSlRYy?(fuQ|UnX0H z+=xq@RNN5#JWihTs3f@wq4#*kdFa}}&~?>vihg8}#EtqnyQe{}tOn@NBMxa`&J(G9 zgL&JHF~?5BR3*Xtv{o7^s|XL=EPZ89QtEcN6+r_|@Nz*D^ z!5s0t!ox3R6`{D<5v#IG3%|XLxfU<`)=@bsbj1&2R+6y~>0wNt*SZ_G=CK6Hl>^-0 zb=Nb0%toeuGbb(?XIlSLC)abY4Hl5Bik<0otdZ(Ho|}gcT{2GG`9&nnQe9H%1zWjz z4PWDLHj-AV_6$?t=93m1dX7z*u8q6J`j_sdY>NgIvD)8qgT#lSC%Z$Q#@d@%a6)qt|bVoh_>yM2mtvU z=%`)=)w^-=wN_z!GqveB%RD)gy1~fK#!vpu^tJZ)XWSro(RO{09IMCI6o~0^ZJ=%5 z2S=MHGQK2VPmh+5*}Hrm;{P5{&wjQd`iK%zIiov%5^f?PQWM7YA|EIXJ0hutd>X)ko4sfiEn z3+=ShOl^OnKY&cPU_32#f#Q2lwz{uW_7Fa5EA#H$ghN|lh4gSJ zG)0Fxdac{J%V{c0j&2o*qLB(X=mZKsfH(Mmf{c|)YZ z*z{fzOT|I7E&CK88ot#hzzr>UTh8bwVe!mCBLsMaOcI8s;Dz)`-D6`T3V-k(cS%)f z8J;u0bEcWsSflffcVadp zAhjWvY|bR~bGko`H}0jzDDy$sL>FAcF;*5d7dI!-zK zJNiPS6GFM9Xv;9aY=k|-TuFTUOCgqB9t#l3C4>Y%{HfUOnXZSgzFn$Pq2v2`Az$#e zbbM}&rqyLeW?0D%D%iD~bn+z!_d=-9EF_(L6hyeM9?;;ASOO_CG>jj zI}tUxvfnAA-$G;7Y3;8$i|Ay(JB9!Ss=2HtUdNRb!phIvUQ_#r%z=Y-71{pF7#ybG z@NU|BES!6ba}=cxelh8uJ=UaM3FT;oBKJ#w<;yO{>A$slnXHYekLx;a6j8 zydChOAwrzJ6p{EN)uc_1)f!L$c(2a_YU<}q_Bc5!o#kLO!Z$@g0duiIt%8|iB~vW5 zW~15vKXa|K)3lj?Vr$0;D9*4kBm{2o?gE4UR#61-0B_Ow9n5x zq@8pl>fXo|9Hd)9_LFkYDZE`xkk5OJeFPNCNzK24pv(dJ?hG{Vj%Ll%=$btdS3EjcSC>twp;g)SLqk{L zB)_E>>b0%cM9^K6{YIZS!%P1BG#&YPf&h(gtkJE}EPbmd;N2_s(_{+rcriUO&sk4l z>}|6zOz*9zn;g~h7Nbgbi90bP&8K+hI+;mQ_5V1kHwApK#a^8M(^gx1pSX6Okky#5 zRtMr)ZS?mMUEPrFv2{qJ-KHB{9KA-l2m$z5=x8>}<{>w6A#fY_3c0%MYQrP9OX2G1ws^#^~Z_P^w&|>JY#M0pSGN5@!qz-LchdWR!S%!U7={lvf5q z%}2<3T&PE(An#5d3yX)Y5k`9&QKgj}s2sRGo;m+={J~)>zYwM=<$;AaG^86ukVjd2IH8zZV)gA3HPK{Cu z(AI`b3GiI8e!WhqL6~JaQN8$8kGUYOHZ?N&4M5lwZ>^}WPjWoHBxkIoAfkE!yI&4G zQ%@GhE1XrdP0N8rtpjeS`0;1!^oo+W<-#BN0aUqi%mUup;>$ zkc8-D>HJRnnwQG?1q6sN1;Ks#EY> zEg$L(P1m%`O~A;VHxnuy2ufIgYl08XAOR7EIU|;sx+JO7In#hvNKP%%bn0Nw{PCDNAN=j~BfTMk@ngvHJ_Er0yCbBh}7 z$~!2S0vM&1Y5e^V7^qF^FG(BwZE|v}`^@)JF@<}5P1DQ$<|^dv0)_PbRa4R!Z6Hck z3Q%>*H1jAKABj6?5&0Y$+Juau&4=CHbrDo%C^lCsm5FIOIXj8$eO`RJG0)jjk82oD zHQPAORR*-ek!Qs-;*YNk>-%<5h>cb=PNTY@J&K>2@_o$RWZsy z7s->o2bT{3hEN?34=H|?`cY{|OcQX$2z}r$bhc@CFEaydf%&oG`GiF$JGT11%#|Tm z%wfxS!@g%(d!bX`a}@N4<4xX8#opgt&54lhb4CHQTkm+QB!4@9Bn5Nu#7%A+9Zhx2 zL5mcvCn7$Ok)?FN!+b{{xkjIB%I?RVA6NYgxD3yM@+jNfqmLAK-bD`7_a0shFrT_!hOHQe*cHxgXZv+gx3f+Z?6z!T>DLRxw;^QE7LbNlg>Q z`@-9v#xqja<<^DEwK|3fS9q@kHml^OrDZ^lUsgxJ+4~iX0rBVC*$N=!@hrGK^7r^I zBq0H9l{JU#AUAOO-5EL)lKOz&0%}Zfu7iHFI#ffdnS!{P&HX2HP2E4UwadidWhT%f zQ6EtQMNSjXck$GRFU%EPfkx1v zGG7)8g|;9^0{iim`7l$tK<6E&3O!%BXj7-3AARpdYV%G@%1~RiJZrLtvoo{E=jOy_ z9zSl2iUuN1PM(-td98NYnS9Lkt>1S>K5F|tF50H;n6zbf`+1L3O6$y$Pt|sQmECSp zAs8fxNWm1oLsK=`G^%f_8OW8r0OW5Vl$q(!9`ej7DmHmJ0F8~Pc}Y{+wr1G*Q!VkhngC0)qInEkklD5W-W19G37qu0YDnczt$YqX9Fd?WrI zlgG__5yuhpyJi8&^0g$&jQ5xG&9{eepz0(k9i$UE`xCW)a-802-0J?M#@=PNZfWQo z3GUMB568+aeUTUA&BBFQl;sF6*BB*Qbk1+G+qc=RBvq;ACw6-B?2}4`&FcvW9Hw|) zKRFU1{E~)TnR;RYt)wD!kv(}`ROk*Li+ifgO28WxM|pm6NbD)F`qQUYKeB)XTU%2` zKU^pY^9tJ`JKt0;S{ir28NL0xEuMH#VKUo?v1Wstzfgqo{NdEH?@R7Qy=D*XtGs~W zwt(0uLDf`$RM2csN3y5ugB_>&vrc5tc<(n%c)Gg~&U5`eaZAY8&PPMdV@#HmxeV+m zPx6Eh(-ruhA@q6iLwg&#GxZMn#<)Ox{jvyfR6HMwpJ9TDRC8P(HEs8^g{hq!am&pvKR;Yofg2li~IGG+05QDbzYA2|79kB_)3V8LvdQ{w6G2F&fec?j>2jCu31I0WR zoT8s(bP{Er-##61Z~w%T=JwAI`MXxx{bhw(DssEeG*ux%9ki{_93?J{=!Yd-Emvp$ zsVyW*X07p)mbj3rfRU)H@f_nPOp(2lYSh5d`7P{We#@CAO2A8BIT1-gFY9Lj=S`R5 zJcPSfYAeZ6IO}PE2G0BXS2AX*=7^+yHPt|!P4#SP6gwn4@{fVe{8E*&9P77}-OM>N z0zD4DJKkvHupcP~2~XzwK`W4A^IiZ}mLm9kl9vNtF6(36-8d{3mqcMDC1K}Zu{mLU zlt!~5em&AEzpf4araN;Sw(D5o{uJ1HX5X1Q-X~oIG4L(E2$CWriPsP+@`RbuN<}>u z6(&RB`o5+_z;~jYDyvuFiMxAk3P^prWi!JG6=Gld^O}3JJX3kD?SGj(g zn+SAMBj3@I<=DO^4npHBTbZqn=mI^VsN}GDWm4r;C{5xrD)y`Fo5&Vr!X*ewbkIR` zkp2G8bRLkqf-=zKyPPZn3e9H_H6vepABA!Nt>~n2q^BC-AmJ6jtYV1SvSXe}CT3dxTrWF?X$Utez34A9EJ) zC?jCTEpJksLz$)RB*7Gm4E#C)wTw(YLf#LP!;;^t(d}Q<0WH5CXjrZdF2afG(#STo zcu?xkYv79{uR?^roZ1sOdI(i4IOsoP@zBvB4)UE!XXjhAU7RqEY{Ay`=RMiMGtGLC zvlgS|zhT+yu_fNC^rA2zTs(5shVBEA`(kUNR38y`m8`Awk2vNn}B7NnHf0}6MIWp8vm zDZ+~ObZnet zE?4~{(@;|d0QiT*dbMJxGZh8>87)Bg1*2UUU1g;`@6(*7KA}|R^CN{w+vxNElbHf2 zPRC~2%zV1ZzA4UipCM)ts@V`j-UjO!K>Y3mI>jQ@Pmfy!+gESr~_)#CtuzafU&7@@}7=J@WQ#A3=&~A+jqkzm(!Jc#&%`B0P@mefkSzT3ajy-Z0wi!oz<)+|02{|6l2D<$yXp|7 zF30+ikt6aCq4`W5vN}@#A^(MHi>)OJr#TiR# zE&&X|tGYM62M+V2)g!hoVZseT1N#0TLUWkOoW8?1{XlSMZi53(*1SwL#?`~=InjhZ zP_Mf8PQY9j-*q6+BH1MD5ouAg$?+!%$|9FYOI)cp`}EpJUhaKy3)Ye`(eb;N@`a0E zs>(<@!Q`CMxz0>8+A z_Y*R~v%gkEGWIk!K1#0oog(UxI3Z((h6Xa89eF6b@~NI~cCpKcYo+vCUj0p%)S!Y6 zupxU5PEJ!h008I&>(cgI?!WnfHWa^Wp8O4c)D5t1#HAQo4^0rD-e)Wpj7+xgDahVU zGeNzcUIz3N)kNb)#_5e-lrzus**CysT^Z)wYYsrEC%Pv1@m(Z2&V*f^&g{dggJUP2 z#=xkJ(QMxp$-Z5uj; z!30doUPs5UhIPsYmg-yw+Fk?P;h)s_HHl~FiIcCr*LT5{h7q6c{T?%o;FceCxI1-{ z+s_z9-O>CnzPD8xPtH!bd9Mr2wFscjy0Um2-vU)4x>gw)s4U%bS(ezO6!7U}R>&xH2AYWfD!eK)|7LWhDgLxMaBXmqCA{B7Kh8mpWcUSK1 zZ(`4Q7{g=8KG&R_g@67OV0(#z{!Ylr;SGA()VkM~Z)JWy9^}{W_n>=s)B4e~fFbaP zz+s-+{|bJ9j2#?2bmwA;Rdj0lT?H8DpW0ITg7Y^#WmoRYn$vg+?K=c_=wC@S$&qqq z8dD9BF+LM$&TGB3vXY(@eVV(P(6O+6)()y0qsfG_i2m_V)O8z=4J5urcGvXAu# zwEtG3Jsh<#)vD_gLc}afbY8P6)1L*JGbVy1vjgwrcRj>wdG1}m6ZjVKrf3zwl9@a9 z+rQdwm%|FW5+5UxT*5P=X?c?Hv0;bMk5Ni27e+1KUxm*6eAz0N=={L|c>wZ{b24O6 z(%3qzvx{sAC5mcVNFSk6)1V|*R+pOXn;kdxSY6{1hE3-%=-?Je3KgCX_~k$si$BJy zljubZ@i|A*ytN)y^5qZ%koChR1YuWzB{Lwo`c%E*W1%GQ&!PYN{p2YL|~u&>3-*SEQRx9f3ekPogPO6xd-?}MP`6b z)Z3?a1AWW2f3zJiTkD;cs*p0bfS=p{)7N++}>oa?O-)L&Xw-_&F3S za_z#%HUk&4&AaePukzf%0Oh+r}7R zPG+fEu>nf;6T2S87p&$Ldw1d=I<=hW3b z1fVj_-`SYR6K*}q?{E=^41JVW(j9Rrg0+m{nr5eMBFFMuOvKaF&|`xCo0_{T>?wm}S588^71j=y)p> zd(4u@Jrs=u5R#onh{Gk!?#j0pelFI)Iu$c87-$&Ys zdkc|?KH9PFN3d%`2C>%I$K%Kxz$J>Ohd+^#Gfy0?*P$*>^1+eR&=dP#jV@jI+6c%& zq9B5ml~j#@Yc5Lj5j4c?A+nw z#NLwgH;yZnFlTA6lEMzI6c(00dohm4Y3?~4hCuKVc1k5Mq-B!997Lbu@cD+AG>1@3 z|BdhDC@~O1a+8tLXv+a3MIa`CM6~$5em}!{SRDL1l%X=%6ij3ovr4J$8q75o8fXk> zM)XwOB-jV7|j-8E_mX90D0}45sN!I93SvQ zIRUituu7B*HK3?0B@PPZz?H?);$^~~8aw-oKS`16D;7$Ft7<8kqe$z^;aT0iMWDh8+W_ZBRZD>5k)5b@r3;)<5I#Y6igEVfuc zPY5UdsI3b*iRZ?Cu>kJyEiZ`ZVev*KYc2mXeNSrF(|{g%p-=w-lQ0NF|C>v0!|jy+ zPVZJ&&JxzX!M){~{IE};-u$eNlKHq*_iU;``Tl_OgI^~?O$i9!_4el&Zod4-%&UGO zo%cIBcM{Nnsmr@HHdhULFwyRGqXAGAhh&!x1u0ryM&i^g*S+gR384OL_OXkIRR~!T zsY><2grcJgLdTl{={(O5w>@FyH2KSTctQYoKHzYe9HxcAY59QMR!IwtG5~31RRukn z)w5;fIoTOg9T66o`ME%@m6q)?!HecbGnD`xZ3y`LfbO3O^e#8@54Og4?#d4G1Vu)! zDOTJ-;&-7=MuxG&%}TvCqyQ}pwOp-NEdXRt<`6W0#G#fSJ;?#davRGdl|)gXr?1z{ zczbAqa!4K_N^@f~64ZopMmH6*rMZd9@muZar|7e?u;f*8e2lzj?*UbvRXZ03a;!HJ zS0Sf^64~S7rb|v6MTt^^8;Z75J#6U7@47dQA?Jrz=A*iLoz#~fCM`qdpfyvW9EwAK zDNi;brJ_$4H+jO><6Da1vzQNtrOxa?f5xTPTePz}wxl}i!TJk+$IRpd)rXkC1fkel zAFK6aTnw5A(q6W`U|L`yylT$@rH_)C5Gyxe7~U((>R}fbgC@MX+ja~$)aor}c3!}j zzG3gEAAsQmz7KF_@}Z8?&1@S*uaX>B00w83EX$kaoY0p4j_YQSeYmqgUIjtyI^!L| z>mLZ~B(4drx0WlLq5G){;0Q;*FzI68J@&iCXgnFfA+35WRm%e>L@fr%bwVa(z%w76 zu}P*4anc`OAJg{4o2AU@H!}tv(|rxcD>4#cVk0{D*Jokj7(|eoZW@4g^z>>7HY;jI zy1$1BcjnFb$X1f-nd>=H2=$T!Eypm|cyBK*k66V^9GXZ)`%K?Hg0QRlk} zD8R+6o{)qsq861|S!d2Jp_f$oU0vev_-7Lm@|7<(@;LH;d#l6nGtDxGFo2+f<2p

Np(O8b*UKt<2FhMe}CQ?R36=dFa<{8Jg#@+Qor6l^Y;@auaUb5c`i~|7z;VH^wJiNLiZiZVAiXa z(~8NBzJfaDO7LfkE2mFAC5R^b^RPv6eM70WX}b_{hgKN z7!5wG@^jH1Vc)Z$8)RXRNSyPGIfj;|OUcyQfX%O7c6A<`^+bhX8Eg67Uuc3wt3nq*I6lG!Dj+Yl++ z$+DEebFIui)+o4}gl#)f9twatQ*a?Hw<4FQEE~AzM1Lb5%Mh)-R=70O z^e^kEkoxw5qLrWe?zEs+DBzXF&vD79ZoRiy;w_IS_ac1|HCj3gg-}0ULP9K-E=*#K zDgI_NnD)<|PS(Ig^rFR?Fk#=<&2FZG>#J;@D-sSCkOyt%+i2lwvW7$B`_D zPMhoNy-L{_@|o-!JZ}crhVg*81O0-dQhK%%C<+)we0MopZaEF`6&CkgAH5?Q_?IcI zRNq)6fWJHa{46r!wr2@`%mDAi-$jNs7&c`sM}HP>w${?S?@d^f6E z>N@O4Cl5k@=5dMray3@^Z2Fb-Wdd}z9`o+PewBdEbDGy8%~u;_y3CR>H4XJlQiGPp z1c-T9YDx{rem) zQN=G#mC9+gp+R`FCDAnPHh)+U6;~hQ`=r@BUVxxUTPI|`yKIi^ZbxsmYmV}?=s9UY zlqW~Yh(WbM=F#oaU4cNX|K-v4Q5i^cw7A*V=3q*;P5pi$w}K??)j@7wc=}J~2Rm0V zd6MpoC(~_H7pnT+sWy~pK0#|{^IS+vhCn`GzD|V>cPw=3`s|lVS|B~d;dWqK4E@l# z)YMGcUkK;Qt;+N|rppKs?j7%;c_C-8f`u7)qzB0uVU z5C0BUW9WjlZNzUn8*({(_A#Prqde@o=q`R0owcNLLg@7+$7OkJ&wG6vbv)nX zX-4RLl`jNXZ1nd{>{24Z-q6uauB!nxxsc}*@un#^T&awW_JNa z30ItgAB48_5Rrp}(C(~g8WLVMpK&dfMkL9wj#2;)Vr7C*1Qjn>vq|R-!{S5Mr_!e; zRw+2JmX4H}NTylSvUZkhDgQFBr##e(ecZR#n-E@C)@rLH(8F^z<4NInU#lGch=s3f z`=E?IH=q`k1z6V698FXn@~lZ7wz zi+)MI`?z%keBv=*W(Y`*$P~|GwfTTDnlo@3dhAGR$hxp5k&sD1bgAoUhZaMAes%6= zhmx2Zlf}N6!{Lv!rzC_{obR!U0SmIog#w5qZjsivl;Z?QrP|Dq)Wsm*WWZR|fksbY z?Z93m{^ZS04AxmFb38i=@^U@Ul>WZXbbP8T8Y_lI7Kj!&-!*(s>NjB z`>XJBm|gLrZ$Pt;u#-@@w9z*PwdjWiYX4D}p|bCX__41gI?9MqA7(!99sLGK2HPGB zPv@C5qE!bhP+90qp~K%?ns=44HeI2+m@YyXj=2`^+N~g_+MaQs%Ie#VeQK;xni^$N z*0?PBop=(#^3J`voK!m&C1qRc zvS5~_KXtZHcVP&5E?$V$Z{&JG4g&x?61}&Tyn)hj&BSoeV~!!Yhz^+vaU@#9wXno2&`WJ{R+NakhaYSdlJBqFWSU7rb%aHEXjtv8LHdsj@K% z5_pM!m>7r#KoQJGSIG_?(+kS)9uN8%Z;u!krm@hvVL6<-@CLy zL7u8y@GFS0>mqv8{=@aKbF^27jaF~^T>1PA@sL?h2f?uA(HZ~wiS(tHpBCK=XxM;7 zfr3^e1wDMIy*900jUf3ily^NBoJSEqL|>36KyQeNM2CTEsyAy6)mnu$}2@lYhj5s6Kp>VRULsP*!cU)%1uOb2cldCGKXI z^dk1!^j;Km2L}Ybvx9H+FM9Nrx&{t!-p_VKGP8P$EQG{IeP>(@HF0&I+Y#l>&$|_M z6FqxY3(8Hb!*11xXHSTbl59V1km;dzJI?S2W9D^DysgZDLbG$_%gVA|)7cVx`u&SX zZ(jN3v}-7xT`|U0n4Q+gF04lc+i<2;V)5S(-lSjU-f*#l>oXY$x7Yg#-fjfrP5xZf z7zr7PMDDb=GP~H_C{>6_oPSM?J@9Y2uJnwngv4?^d`6&R-km1H(DFNn_50Kr719oR zL|_Twvnuo|wf!{XF?Mi@GwU%2+ux2j`8OBnJ65Dx$fpouWRRFgPfYq%M!6T=1welB z{JU$aH$4?K;n}IXuQ?jNLvYXNst8xTW2OeizZ2nPe7LZk0aRxAC+f+TwM6I~T1??P z;@MEEOEQj@&(-SFg#~6gCtKU|0BunHNGqNiZ2I3a1juvhPj^VG<~{eGGNaJ|D?2X> zJZn(r0GL}Kt0W3ZHLm?_HG|sGyp-g}vT@0>@HPH$}XCDM#w*~F*}6$s!l zt$p~#M%t_=W*J8y`Q3Z#$iImkVTd=x6LCjVv5yiiKc63A=LOImz)c&2p!{5i&c_QI zw{^71^`R1m5@I=v8zZ+F29P@J-fDG2r}B^AMB<8eQjxrA-a})--0pS;{%OVgqFZch z1e)K?<<#$I!8tFiNz%fFxb5G2pHvIL!A*_3)S_h=qS?5E2+T~;B7&`tj)+jfVXpKOe}17Y%2~q5P{8mz~s7iiicHCZ`GpB6`~KZb9af8DxK5641bJ z#XTqV%WEz?T>d@oKGs3m8^oz^Df*xcTH4DehFw-N%NuVFI!2k~5Wd_uH&HWNWD4jt zR`01-g{|LH6EK^RW$QLS|L2L?*mXOW8S>&93MJ~J5AgRwiCpFgufvIvG1B?=lnetS?TB%J=6J2buaG@M9!vkl3cbs-Lx0HsD z4_*EP+J@KHuSu*|4xfQ*wd)l<9Zi2#rUE?vo=RkRc94Z+fXogtEN9szOAhlQPi*|_ z>(%!U@9YhtHs#|@8nW;}!GWa(NxPq^GE5S{j_&P>qP%HE@4@MUef^GHC96|DZ3Vrb z4G+(L(MIogM`b$=t1q^P;gqCw3LOO9%ysKaGZ{QM^a1(+FpSST#!LNb#bpU5i9SEe za;M7>?*Trrjtp~iZD$|HE#W?fms@o)Npw6pp@IZy;$e|zxu?;M&{N-1J3&9!m@Bi0 zPY>9>86d;9yZ6j5BXA3a+w<~f!dMBdw718)&t{5@w;yj#a%U+uL!H=cB`iBu8POfD ziUoE66yhY9sjH;p)p7?YX2&gBLJs(F5bC>d0nB_XOrZ2LEn(cpm2*AK^ClZ47UwN< zPC!<++(VR4{`ALmG00FodC<>G)WaPiy+itFheM1xrBSIp2}*CA`?Qi|@YUR{P+<*-3?nFX zv@5se@I*@3K>s{5awz0A{a;D~V$8zJdU+=BJ^H*arN7-juP>G9QR-h#E+Cq7YO$#F zeL@)bn{le!ZNy7hBkEbL^0Be4QN6wKP0EzLB$~f2nw*M`f4uyfP!^gI{Q(8R&+E{( zONo!8m1<}7u{Zi-VV%1p+sw=i@iFY|CV!rJxR8>N=>;&&v{da#wSxvMUb9E9sekyf zF;qMV*$gN?@h>w-$ylfrNfSqn(Q6ZZ3lB_EHrdDB(dA}{*78l6QlZ2}^`5lDEUUye z)JBP#oZ$MRW~!`BIo!p^c}TqazaYhJz)`fOwm5-9oYR4bFs}O%8mDoaee$W6h#|$Y z#9$yN>{bQo?wqh!@g-TVyfi4e$}V0BnH0<6hbrEMBOI%T-E@3gr}_hEI3IuA3Z@R5 z<+f!|I|l;lIo(~Gjq7(+iSDvI4ISQ)0)_p3AiYC{Pu_m85Y*Ds=^wq)4r;HjJF@h68k9p8| zmO{ziPrzyFaD!Cu5|qvYieCG*{843?lj)kQvQLMJ;-((Vo>;Vxzt{q^6|vn43B z+vdpn{q?e%hqvqPbxt>f_MOWmp39E;;UfPIG9!4#*c+o-1UotP6zZLyoAV?inD+&+ zTIJ58n~RWPW#T-%nsg1qxDT^lNQea_8~0y``)*fbc^;0pCnwSHz~50*C}D#_7ra47kL`#_9sk-H*>nlC3{f%Kt}>7SFp@j*DMS zuB8YC%Gr;uVgYk9kP4<@cb=Gxq)uJU%_!qXCL;-A+5Iy{R|l9ww|;#KQw2oQ5v4Lr z1`U4<10J=zC>dX8rS$l61I)~o;?eeuFiyK62A!kTnfj&&mFz=9GnQL_uHd=^Wg*I> zhL%7pXh|7wW&RK{Ww_wqc@3ZmhgrV-sBbeKSt;J_R66lu;UJ<^4w?-St^Nd1>Uy|R z>J%B7UamaT`RgEs;N7ABZA$PzL#L+nZz#K;9Ia*)aV0yW4c^}~y{`k_vujOsxFI_6 zr{QiUh`2qJwZ(4_vw3XK564E=&!~;dKu6!IBtT{IPvwv<9pqx=tlW+kyaeoh#L=~?=UXeQCZ-XoJ>K_E9($;iZ zAhjR}BL8_HlS6#Wm3Zh3lFh{q3z*uqX2Ga;;)L~+*O6<9!P4|A%Nq}veF4kqZf zP<3@6cz3tC!8J{CSM$Ph#OwN<9)#TMWBx51bdzHw*$b2?)ll5#8s}(ee9dFTn#p$lVN;}pCCo3!1E^aDnA?wY%)XyeSSos0(mrZRbLMZRWo`R1;2tQlV+L+Mhok>&v~l4 zZr!OTaA@I?U5aNb6JcC-LnWjBgow!4-%38tOkk>r6ybsbv7{NnKZp+C4Dl+!PJPmD zqekdcURCJ*e%Z#+Y!DkR&t88mdgz0lgIX6Gmd07e0|?j_1DLm&zbnT?1*CXChP?Bu zL&)7QZ$8VM@Z2$TM0ob6Qah91j{W1uK|>)$V$;Ir;L|#SHm}{kDLtgBgb}ZiNh69P z6+L_)2?-NE#RfPRyQg11*}4YFgQh(uuuDa>K)W*Q8Xg z-kR#hJp|(Fb?V8I9I$SuTE1qv*f_u$8R83_s}`xGFdG z&n&NBHwAW^QRr3Z&@~`9*{j0IDSj9M3bHp|>ko<7 zG>?9kj_iQWs&NDJP~~e8HODO{FfbgET8|EOe4Rk{C2UAQ zVOL|3!&!{Qk(Lx(w*K~F>c0nkPR`9?XFZGV}1_613hwL2~9V-Eueji3qKR|4E~1 zL;?XNj1#s=p>D)neg)n{3IGl3wSmNPbBlo$d_V~{hx;C+oZsUqpN3+K5$NRM_sQz> zJLAY?Ac{v}C#nJlcH;kMV54Qg7^fE+po^BUF_iUs+J6olKN}Tj&ohu;intUkJpR8n zHM^pBsKm3l61$HBycT%4t-pA+?xR4L>Y+uV^9sG5^iaPw{CTz5BX4{$w1=6lTP4M4+vJS zJe%l%aVk`ZQC4qCqZ*40muL8hGxAN7lKnqXeVQ&t(B?zSF2ygtJ3|I4D*n4g-BKKp zX@OXqkCox!Oj7v}_8t{!ose@IkS_qX5HAqv#tk`*v+(kvr+j%}Qc?yAZ60INcqs#( z$`Fr~g~A?)M58tx+sh12Pi1I;pLzz|qVQn@b*3`kP%;z4=w^sDQfWLr$UuA=Ea4LS z=L|0BLA;zJPMb{bda~%7%y3T*_P3mY5e`!Q>X(oOL^0yacVt@KN%7Kv$le_APrX=qOP?DoZgbj`U9 zpc}(rGWNx-YGLKW&3#ez)p$toK0JHvT#tCBb2%kepg&m7J_r|fzVqL&gLwh}36vB6 zmK+lp3{F+Bk=%Y3ED#IQM(J4p0}Mfy^8cgitK+Kdf^JDcLOLZBK{`Z28l^!(K)ORv zKoF!Gqy+>Ck#3M~kOmb2Nu^s-x;yS1-tW8jcmGt*InRFfo>{YI&FsC!B-M1lRY93x zR2N^gzL_MjjIgFC7)O7{#N1RBEQkZj{^t6I8(8O8I|>%cWC%JTgm8;Vdai#ck2D3a z&OiFGw6M)G@n5L?&tIjtH>-Qv>;GZbRytq_|WQ9#c zl7!hd*gt#x26q)AX&)h@y3t!G(&bAc$MQJLq7_cwfQI+hkNB7mrd!`Yq0T+(_Vn$q zH8u0luN80m$Kx^D?eO!KKi`V=;dgtHcgw9_WL;Z8$X_IYo8I<#8ZkR==57Kx0l4W6 zj0-je#u+R-unRFHi6cc2x9mLJK78d)(D0JpqoF6lkb|-NG{?;1{_6`mI#urz0q7O| z4jd&|7RAwuj4mzXMhhq??lGR&OwAiwE%W^OhM6Z0yF~;p>DRHDH z`$B4zY?HgE`4|0sng6PVdv3%lvze4>{ssy1MGmHP%AX>8)ox4ER2S_AW0I_(zBcqE0*U2vh_Nb8aJiv#@yM z6-`0jyUbifJYjhz&LEW}fU#8^W{5hj_568jbhusl&xtj_wGG~z12KF^NvwMw%ye{v z!SCSgQoGrAHEZ~CyfEFtN5k{_$$jQ}7}NTRNmgOOvg@DCf<(QPuKmMz*CFlsZv+#H z`oVE;3>%-dQTwZan^V{S-`MQLZggn5GSPF{1p6B5$+5!jiP^@|#(ASSzsD0HR0Pr| z0jK4qi6UUoMStQ+>zG0$5Q6YzQPErg7jQ~Y z--l#4X5d>j>@XX3;8|jT;Ss)jC6E1zg9F?wS56Fp*3l@{w4ur`emaC1Zzy3$5GMsN zB+iB6<7PeCsVm(ux)`|wpZ%D8lcMRG(h)>St`X9usd|XI@ioXo$d$)>^p^XwZ!F{H z`wi?hrw*qkF{8{rSjwsZs^mf%#GsAlD1UEijz#jAtfoh!D5ZqVyiI-JIhX$La2cvb zWtt{uU%_px))RtdySn@GweNpn7K5)@+I)sHJN>WX=JqVzNLfwhJXO*4Wjn7pG*F8uHNxB9acd*&fFh9`h~-N9de(}`?- zWIx@}|20AJO74dsjPmkH?0H@gf;Ze%AB#j`K@{7fQS2+$uBeJp9W2Jf^j-v_t3tzj zOVR|bfOxxc-XQ&;%%f)%GqjtjIu}Qb zmjhl`yYs^z?7oxM+Lkx=$Hufqv~SOorI)juQc^JZD&8uz8PjZJH&%lUxA`l)N&6cbq5m>SmxN%7YQFJ~l zI+fV&`SNJFEMa~*mYcKECM5z}&+!#s^76sy9t|JnDtczSso_NWms#Lk$eNXSp8o6E z>rbU(Aya<*5#O_>i#0uC5R&y^*?A&3`t<6}*2vvxEcM-wD0&z__5%W};PvESJLkQU zvS3Jev#M20Keod4(hKhO@GdVs{E%bUabTaxQ(ATP)<}cWKBAtzG*1O!8GP0i4?or$ zL`kZG$33M%+bWjpttvp_GMBY4hGg*u?luzD4TJYXPcLTi)Kixq z9lDsuUWn!~0;Bb;XRunN3(54654D`a`Ed}0$M2p9vaRvx^L}PY_AD4zii+aP$C)1i zv))wG!gY^$LCQK#opP zBcF7;{adPwU1?>55TlEO2uK3WcE}_^n+c*^06KEXS|bg8?xDwJtC9qtn#XS&jT|;NP4=tNH~+yyaB-a@)1hR<1n_Uhdxv_0s$AgEE9a-xw`nvL3^`msb`!kRwj*Mru3S?j0ftN5Qp?)#EKvik1k^TW(URRV&L zpk4XnP6ZV^zBi531?P4dm>>>zdDAz7*=M|n40O-c`VF^tUmDu$ul4QbhYa(7&(wgm zA+)%TSQ+Q81XS#@=V|Z1u#9@6q!>nzt_9Nr8D@s_aE_Ps`8uW?S80&mlp4uTynsE< z>_QNX2Q~8sIzR71CVEiiO6zeP;;bff;pJjWy)L}ob0GOw5oT(nh}z@Kpw@!B@@LJg zY#{|}>)vPHvceeeX4>LEpSTI4Dsyo_mkHtbM!Ky0>BjEX`DQLbYWP@#e#(sA9hoqB zO{co+_;R~b^tfHfY2M>aWBQuGxT}yD*{P%doThH(gi9%vWP;i|%U22Q}SnC@t{ zkk+@4a<{GZ4{zoBu5RjPn@%){nMgxeJ~qW~i;`%4IAx7>ckFF+|IJ3zP@5JXWX(zU zE&GpQX0ZvbSG7e|>>~H9#uE=YiS^2mY%+?*HS2rEZ2ev^g-=9B^ zwckv7;}Xo|E^3;?WCi4j2z2W;i%bdlRPdV7j*^u;G_2K zfIo)61h*8ms=1#_vB8<@|9y@9p81}Vi|t*Ue^b@Vq-ZwObYno**eb>dRQ`>1ULlbE zv=-`eptZp1Kh^7^ZY@&fIBU4Kt7~j#R7S^d2b)39By`a&a}mP12qRB_EYNH< zJg_^-*FaHUJU%DvDTCf&GfKsiPC8v@-HMzg1p0S!reI`C@!`(NvYfzkT!`=QsLf^1 zv#0IuSxk-{6fqCxs&#Uo#`e$+yuw1{o1J1L+3ct+|9x6rl9?fVh?i)#l3=?c*Z3@D zG<7CjSYQo*2YO$%zmcf?(@NLgfPwww{U?JMAz`FJve6JJW`NGjRw2=B#WL;XN#9KM zmh;uXIFX)P=*2m0s!)TnDQ44dqG?I`9ZV4xQ=Mwraqw-aB;1#=$*`L7ddRUL=Rj1r zb@BDFS!>x*VpD%pM%~`!@d!TFgrH=3$mhWq1e$^J%8JJ@V1?p=&a zqO?sWUSogZ$%OU@FazUO%44$?do2LRJ1tQM%nj)57nO9yV6PE*G_NvvWvRkQ@X&AMbRJE z?pSw|?mS0(ElP%RYQ~~1+gz>PHuRx7o^miWc!6D0oPn?`4WhoRuoA_sj-w!>{?t8m zRJ%bVa)%_bWgal%>jr8M`s-K$dkV zOqZYKBTtGMRK#rKfB?w_PR&3p%j+~ZCxf`jotl^|ha-;=M_fB9Ik)l=?=t=loJyu` z%8SpCgJ6Qw54X;d73;I5;ZH_^jiL=hi>dCyzuNRS?pEF zS)=>p!wP+k96s;EJazVG5}j{rkPnZ@`$ltLbofL2<(qmZ*&oPKg9Ue{us@hO94Irh zR$o)1=B`j<+nxbv8UbrHd#Q;v({$qnTVU?A|F|Hg#M4Y4;TCMI7mJF^EzIqzm0D3e zD&h>-mTi&2!L>2**Q=4gh)g8icAU=TN$~WHxO%gEFj*F@En-$)EkT6|r}1mcH=?=s zQJcTyqpX1&l3wS35$b9fVZ-C83SsH#tsJlJ(KPVhUMhSyt#4$>`N+#>@CzbD2cW~b zu!mLVWDVQM*5l|HYiW0_w(9`Jf?5 ze^oej!}gb7UBMk<-!u#7t4mF^)wWXC+(zeL2FOt_xzaH7cu1j}&pDLh^~}k(Y}HCQJf z-9Ddt?!I-re!^9&*%c3&s=#YQ#crF`9i|g$H81X@f=LW@@PKGec(Ubk5DfxN5$fm9+;}76k)<AKb3xjltQ-I!e8&wG! znYV(X6$#l!UcRC_K7FdyOxq%=r{uzRf% z596zEEH^hLTQ5%h_myOV0nbktHqYFg61;K zw=e0ud!d?E*9!M%r6s%N$)-T~^WT`pz*y6LtqJL=?CVe@yk>I-0p_Pl0-; z)3?m7(#^XRzn*WZsUszipEM(=bEBphGAFKnhlH_>VtU^+|A7J#q z#y(U#xN%g&+E?*yy>pzHR3kda4{7P>9&~^YcXFIjQLwy{Wj)D5ILnG2gP6z=XixNv zJvzwft-~GUGu#CCQ!Kr2$;=iTb{x7`wGkY6fEK=P#zGo zG+F6F{Z8j*4wA4a?q&n6*Pe+-WDN_-T8)Ih1XUk=pyBT;Gtj9zWneAxL@?5FiWi-D zvq%U!6>k@uC$1AIK0--!%5o(DPv3#@kU%$_FhES;IH7r4BqEWv@0+H~vwC{OQYbT0 zE%MJGAUN1ekT;tIP7*N7>xr;WZ9`cZY`sEI_*X+zPmi#ka?SQe5Cb_M?8mG+V6Q0% z3WY8Jb?%q~Z}~`hOoWHa_P)f)bw>~4H51Qy55LEuS%)X?4$37SM2~bB#x=|*hH{%N z8PKCJ1pN0@ZcPatA19WR{|0Cexs*3z*}G!u-O{-#IhBu~eTn{K-D$3mycfNg`A?At z0)tJIqg%4sU|o{*{ISH3rEac^Npr@+?Zka4-p9*g-V;qT7c%ZMkA~-M1{%vZ{+ni& z6K2dOFUx>I$nnF#Kd=g+ry))rq!X}`wf$5x-t{^o0pi$S&vUI%Y?21B`QbWwuklzv z9T9m^)lTIb_6N#0Z=_ktT#bO%cKN8u+l^D&ADMhWxu;J`GRv{}y-e(xY!f6Vs8WgB zM1QW>!Q6SBFkN2aym;4ccNz@g2~5$SRf0jy%{Sy&k#^wWhwEUH8mdapkA^k4-Men= zOeTZ3e>DjUr>`fX&NC;o3)=uFe!>~HYWE-!v7gS)eUcYT!@@k@x|pk@_85$H7;t}q z3ts7|B4lNjb^3@vUss~Z_{jEsGee56Ph&^Y!>(ornASu4aK&Pkz|aL|`1r3EG7>ud z?;x0Zyy-z(`7@0|?X@j@Jox=G8QQH7J_D2?y5#Lij4?!faip)BrwD)9F?@5^V*`r` zC&%k=1jeKj&Hl#c@jZmk=jHqVQ0d-)0COUb9E&r*nmSnIzd9}@xhuETyWLZ8hy1Dj zQZR;|!;K_Yk5>_#Fv^bSo2byLeWC!L&kU@jqeJ1U#Pis4V`49FkuOIRX5Fhh5Uw@z z*o}aqMqMAk1OVjqr{^L5BPv|yJf#?u&O$hwQAzXYDE&=TP2Q+U4+RA}5PzFnO+^9I zI)DCQ6aA-g)j_F+clQQ@97Hz@#u9kx=Sg0e4N z;~9i&Dm@C8Y$=tzBa%+F)1kgQy3W39r&Ni(+}_nw`jT;d6q}X*@eqwACN)+LQu}F($Vjep4}4#Uhg*BW68sZiQ(~NBBla`o zRP3?Dtv6BEv1d>4W~&lpwuo#f{SlM|bZL7Y-t3+`#Xj3S@?nU@G@iZpgZ=e3X)UX|lz2>`4;gcZpM2*H7Qw(pY9{^J>v<886& zD5bjEU}DkqaH=ju5s;Fi?^dtdN4BVULY%J*V3k0>rUwg{L32L$)}DbC^%1Ld;`iPZ z6OWXii3j)5&dVUiqE`InEKp7h&oZeh8TLfg`ri-gQscf9s;XhW1)uErJI8VMpHkUA z&Gd1ehfn)@3Qa2RrDY(-O^6K_aUo1T8tsgV$V(h9YMwzn4e${WqN22}X_4ypp$~ks zk6lB+|2v6c7JUMxN1sjE*CWu7o-~;%{ADac%B3Pw_6$WGwk})aGQZ@Z4?@_%O_}RZS z9ZNn;N68341Ael7=(O&HT{))ha5>XHU? z^j)fJf$=&%c6BgVMeOxNkLg{2C?$pvnpHgSH3&?=F`4QThUijG|*5KZwMm- zGv^yKao|PO_5|5n9o{(AM_41_|GP%#00JyW&}GPwPuG$O*;(Xz5ZsVX8x>4_7OuTL zyB5T)1&j=V6=@*E(-Dek;*rFj1%p7X-q(n?#V%`bC%euL?M1OqM{f4gF<9yai#$7S zecgZ7^a#QXIBbTG{NOLW7ZmjQSUEg5gXX5txjc->K!84?e$43Pj-notpp z+4LF@VPiC!#2e3tL{ktFfXY0$isY++ZBvKp>%qW0Nd#&L+9|P?YobLHVZA z`yZR%fv5}A90t%5wS%z{WbCWFiHQ$gxQ(t( z$aA2^v_0ssX@r#XOR*23>^nHVHOpI9y*8CO@uGt_)`+xt_7mzIn;~+)$T+P!WvkZ- zm_*8zVnO%pMoJ>RglAi;EZQjUrRU+37WvEM)+UNk!%~c~&Q;%F;&^|x1!;KQ_tqdgp7`>BMictU_|o=0!C!B;OX64#O2ntar5Yw%XgtJ8&CjM(dh>U?4* zjSJJTsnW*E()t}q;&>A@7j$|S)397C;e$UQ9T;PWNju;fu`RvMWrh&#z~u3+|uPh)%lQO*f`=g+o~CP*VR` zjZOa6Q2EF(bz@^rv5n(q6sG!f#%jbf*=hO*9(Wr6XZ_M=)YrBMG>ty38uvmiB0C>L z;pNW2M0eci4XmU(2mNUN9+xh8UwS{dr}E9sozN^4#&dIw zxNrpznt*6}YgpI2xSB_V45FxWXC(XpdF(m8k!9+)+;e)cUt`a~dc+h80|u&$AwrYB zY2G4_s!C_1EJ!_s{RKpCH$F`BR|;wZ$k}pQuW!5fQUAOYYf({>+(dPnj+$}0-3+bR9gMzOb6d0vI9$+ z{;~#O=Q#jI)%I{}BYcAgu;lR~gI%Y~RfQx9jhLK{xHuVc{ffL}Ex! znrRTLvp3SBK->D&CeC$+{FUd`1%~kt!eb+XO3onQVHL`y%hzxdZGEn?X1jZ)x$ejN z_B~lvHRg@NhUM<~ww((iu@qRkAf1-jl}jI}zf!T4wfk4b&$)Up?!8 zo3t$ELwz<|9m1YC7P>$OQ3t4G6o z1i_BmAxcO*KNy%m5Si%IrQ&zZO4VYyCV|puF5bw*=yN|DRP9ira58;Dm04J4{XTAB z&$c{1`%)AX{e+3r*O{yZo0jIH;b3CpNv##e)d=VlV&ndqV{;mWP=WjulDw=3g-!xi4h)A6OO44@k2uA*WbJ@C1ZJe3EvGWIayc zF1{ESLi*uqXMVfS+c*3+0hDUeXe9!mPDS#$|XI=aAA&`j& zyFL*S*hbeg+{7+a6e(A@ROquK!QNd~iP=kyUQpeV^2l!|y%bJKL6{$R3=DmUbkw2c zS`Bdey~d5oubTIuBPP>Gw878 z{^T&OjJ8y?>kY0R-3a;axS#?$XaJK#`P68CkG~xylBGAGd3j)*|LwLrl|61RDD_nK zSX=q~vw^G=J>qd_G&5W*!Lec7F`Ze{XK-`*y;2|a{m`G)g3*+#%Tuc@!oT?USFP2Y zOsc?@P6HMS?~?m8=|?-TMLo^LiN$e_zNcV5cEgGgwz&*KvO&_1m}))#EN2f-^=M`) z-*iMgi&BT+(O!3&_wF8-ZPkD2ggPP?C85)486KC!{!p9U}@fT*Cw^Hv@P#fK`qwAqu9uYH|d6 zPV(#XABjkC#E;}%?6{vMtZmgvokN5oC7NwiSbr> zABh+J7fInfwxA#Vb2bi|ZILv-CsrO>KEcZHQiR1X#nQPvzPyCe+u)64D#Rk^6&)d# z{BLTq``mJ0i>`ywuR9>lbLSCaiZ^pOO)nh|x7ZrKlgZIq3YD#f+(iLr1DBf0TQ)iMsN2D#vG(iUw zADeFwh=F4=2;=>r8nHjiaQs>i$w|i&WQE~Mqy(MMb)B_e$nUkBOvc)sVlpw8{wVA0 zSC@Y~^v|v%AWq+VW`oPkXn)yy3|-8V(BKraEoz}q;+riv00B6_5By)yDiIt^B_TyY z{OHFE7AOnQA6e)5rHbIX->Ri8VG3}!tzmPCJZ41V6{&G>uU&Ray#MEI-l6&SLBZ^y zoQnD^g1mBiqlvj=efcu4>n|$^!<7m=2ylw{BcOWf41$fn`T(E z(xF?0?sZQ7OKY%tFU%~Isq9Ioq_2dz*l#kLM$cBAM_RTImmr#F$Rm$96cC)TS7YQ zj0%=j(yF7Nak=Z}{k=dbs9QPw@*H_;V=b^^wUgHyed{Ww2g-Ss3`bY+7)dNrN;xTbD8Gjz+4`(>0vj!e=i?S-1AB7ts2>T z%43BtEXd#%La5b$r4TQk%5hnwkW~aT_XPNxt$}sj1#5hJXM~(M;HUR0rL}$A#NPU{ z3RCqm25Q`p{jg=N6G{vTqjxy`{S&&?>`{p{Ud|*pL9fWbk@pNQC5owpw~Eh#W$qYte4Q)&^`(`Jpi}c51y(-B&5$(8O!OIKg;4 zcY9k`oZhvS_|e-|8sFR*|9CN_={GRjPPCliG*6i^$J0WsadLbP6i#Xqts5LF2U9)^ z9`CI=`JWiYgh)>K}h4>F_@zk>qd!ekYcRO1!&g% z4|}eaA1VlXpD#p6u(4;qKAhXM(&5}lC_~%yB-XIrwY8z^0iVvs^5b#?&2~?tK2a5l zpqt}O7?*++!nC0-_dx3~mUzC}2jM8FQHYi%!34KGk(I@##PFtR#Gbc)K6eJ~q_g{4 zwusPCTVHB`MdX0H6dd=a(rHq>ve)XSRsLTA;Z%4(F8uLf5wp&5Keei(F%bcr0#Gqm zmcMBv4^r~Qmq}|X0}X4%fo3~`m`CM%t>upQ`~0rlu&Or>ojpM+GAnzAx{h8cfS^AM zk#(%bCrjTzp`au7Wfz)j2f12JlHO1;1zlO$8KWl*d+xSoYj9H&XSXIOwC=Y4cN;Ue zDx7Xl9+5)`n#aA-31^|3m9?Re^Oi0ix)#Lj-iL~t!R6@v(_?lj5QQ}2zzSFtQ_L6H zILyCqCtDe7(Rz=>a3oK(i;QS{#~Q^bm*IwQFVt_hV5@kx%pAyhL59{H?ih3N=TEEZ z^(Y%0CyL@jSkWi(gpO7(q$TN}8yuG&7RLHt*RvX9 zNi9CKc^RDxvuB@)QP=IYRJeZ~m`W15?~uRWs-xL%>}yGF#`UcK;r!mH1ug)g>m)+H z+~H_A4LRF!GCw>ONvkjE?t)5Zd*tf?In#`-ijo^%XVKxB#a7$4HqnNNpO!-3yrJ%( z`L!b-vDjLrq)*<&xukg8|5clNV*IK3ewiukf-ojP=x-Z!n;jGJtqWb50&tI^x z0TKk*>f=&(Wp44C-aKEp*}Y1PsB_!5jNWCh*$~52;Qy~eAY+PIy&k$%C&Dt<@W2U! z=b5|Jx&p|VL?JEhwyl3$H#>x?{I_P18img4i=R5TA$4mAyiwWrtlsoX6}`#nnKf+~ zt%sGj;6sF={jR!B01<1WE2=d+MuZq<$BsL5r>jzQJJTM-LSx}gnb|Gd*0Zq5Naxph zM|yZuf~WPx)&s>jO->AxqMcK>klEa?79*`2?4MUPuYH`%_L0BE#PK%%;+F;lN!i|U zS__Sz4D-ev2A}F#Lag!?r^_TIccFmh?SAi+=`_bke&p6=G3$g&%UI?t2EWAB>wzQP zMnueNsA;Lmmb(RGkdecUA?V&5=nm?X25zF3h)z(cHdvd#r{*(#fyCEE7tI;h*0wHA`@|xHKfz5 zXD_FX?0V(Nr}?kL#UJL-dFlpW$y&(G4QneKVhtqINw~_&kr$t$WIaG)?sN{ndpvK& z#VP;8s84Cwr@AVz;4dj=OKh$->6QP-%=lxdZL{*XFLRU{u+f$6(nYzjlrj)qEPapr zO$w!vz9wQ3K}agcUjA09J&O7kF_2E><;8e@W?Gugaybtb8uD>QI4K}_;p3_FacaEL zj@!|^XMLMzVqk9{%1xY`W5!qy{O-_2he_l5 z7*Wo2q9Q-?5iG)6@uM!Z`v|FVIf-XU5k z>RVJl6&ZOO#aTb+L1RLi6~?1^m$ig)X8G-c>RT_^d{HrqY_khk#CIdfLh|%q7LRFS zADvUQ^{lRPQd(6EK~SyvWnj$Q8GhHhcX>`JbjRnnbPKM9)nsn)LQS$e`@`%n;}^%r z#@pFp`{}|&P^yn?m~sp0^V!_~9+oa+e!hHDX8p*l!vK2_iI_~h0}FHwsVg0N{gW7+sEw-l*Z2(?!ze^% zWJx%tH(J}(jMj>Wk7#+3UW@dhoPy+FwD!8btd6m(cB(?A)n+-nB%!uapB_bRx%J^z zO$xG`hxhShKoS4T5>cd*K0oK>iMOJW!?sU(Zr-rIin^Hl^1G0t(To(vp?-jTyxd%Q z9_04VrFQB4exV$ckt|N6U1q<>^%x0hw4|U0b=gPn-`a9@Dr8miXH~AS!3}qMbA0-1 zn3E?AYu%MBVrWVW@>N|YZLaK7pR*kYnRfPNW?kV4=*PiRikQa6SP%R`O{OK?8AYds zznJjv(0~FbcF|No zOlb|O(xe?|KxuWcK>jn-;kx7W&Ik$1A3@(1TG?r5Dp6_NCMbVb=NR%sUrtvvF*IMK zV|kq$m0 z6M{#MOdd~7uuXL#PUYy-P;Ywo8aV57&{$-; zGMx1oqI!FGyTwWUZX^_SMi$^3rTW_fg!cVY_)CjGe&~ z$Ts?B)$Y+1^fu>jtW7wyoI3aDkDYqy3$<)~G?Hwtrqz|CCn_38Y4*Cb<1APz7Vhby zVQ^kA2nd=k|3wsEZnE;HSH6X?hcNuU9aG-!#qGD5!iaS1&D9p|;S=wy&DiaaLW32c z1Bdi=D9n}Ee%*QtU3AL~Tu!q4%Rz02UZo!QtjBLc$&ycw9wqyGe-Y~bDvre2D0PXS z(Ye*dTV7#7UN<%A{$O*0PA@3qa28l5xN0hw-cE>41f1x|sa`kd%OWeB{`}QQ{v#X< z6W`ic^Vn7HRUg9uOwRoDXH?}zNWvRyB({1lOF+ReIhsbnR;isX!}i-=RG7<}KR490 zdbL_O?Q!Ziyw)=juWji2Tjsc$2b!X#tZ;6Tay9KxeR>8 z`>On}OA?Hbeo(>XjtOGRALIN07PlJz8NAC?nU^?T zza>BM{MdRfCm0j2m0z^ny6IW!V7T^iE1I3KY%rs>u`o&FoJ{rzg}zF#${$$-l81`6 zYcbCncy>oloj>#U07T}0eA&dwdSAk=9nZFm2Bj#LfL#k)%wzPjx96-LfI0NUYSy`= zHn))Xpj>cE@@j z+Z|PLWt22qg=!l6>RVsVz99ee@YL%d=!fcM2N55y1hn}4(m`%^7jWZRbRcV^=s0WU zkZZOh&-tZrDVfTbECkI@HS3AYmnxmgG{Ab)sLjQwyNoSuuV7y;U6K2ogv*=2v$ArN z+OyBYs6+{0JQKp-ZfYTS^Ghj*6^kNmar&WF#mz;_`s+d4;-@;COKt%-)9rc=f3?7q zW{ysru;JD-Y*TloAp6>Rk6If-J*O{1-yW;VO{WZGX z8x^oYlrH)iUCYO#0@hgo&S?}rXcAWF#zkhIi72BPjg}LeZN8W&ym93kZCcX6F9?=z;C!<~_ z55Icr@YHonhE6Dw@>2(XLX7&42UBZlwwi|VvE0<%Q0{3TDXDxPYx(8NoMvCE;Y{%K zC^R-c&*6NBF=Kb+#DY2gHuh;^`Ta}Xa?$Ev(GiPwdde=wf#&9$W42@YjJVYuf6Hoq zOh5c?2;nW{O@t3tOH%A*G1L-uun_#Ztx|a^()ks})p^1sm9zKXJGEO*-8wrN>qN-l zW3(bBGg6Z0+r1tx3pUOl2QpBOm!2O|-amnK>PzDT(SQB74fbZ(@tn;c>*D3pBwPYz zR(`v-(o~R-kmCN4+-jeh_Q4~or`?*I?(+ERxbLj*#ljjm!Pt5viYg)~HDhZVZvI7h z8)g0d!QbbS^w6#uAzI#4i{JEySvfuGMvjzj+r&ooqt zX9Q7@N3)NlXI!I#XZ(}t^$kvH%|A-?Rou{V#}ijfzR=S!A=_*eYVQ~AFNh7(1uQZ& z#k}0t+5fss6T6+fR#+@(2+Gh}#q2>sQLZu>$tcqjc8AVASWh#7;g~90eVau}IwN-C z%PomAu@Vr}PV{aQ4wCz6TC{~*w3nnrmN;uY?!UjP&n$p0<|FnDiZ!v$wDDERvCy-}{9QzAe-Px>;+Ci&cKb z^WVXXW&U$>%%y@|s>X{A0Rkv0>`~WzF`#2Z)~9CYt;^m{US++g@C+d}9AecE56;YuCsrjBT45 zSyD2!lS^4ewd+eY^`1s&ocQp8SC?J(s1AEwgmZjrwhRr`?suKt=E`vj=MHEgcphIV zX_Bm+_e^lJc*yqCOobAE^(#B0N=ce%=wdW`A!|r=HjwvEZTiH;A48&9z3ihXE~s(u zpqRRlEbNprc%fQ_TvW#-+jrt{6rC7_+!N%L0kkonvm3cQ7;v}v%?ZC4QxMjTv(Gml0Ux0#mbSL zz}+%kH2z0fPK3pL@1Z_Ku?OLIUAA#O&PJ$OKTnBr52eDb(Pkh2D-#@wY<6_u1(X;J zxQUBrSW%Xp`zIQ!^sSunhHG6$G8#=eT@5qRg}7g$eyX8-!i*Cf*sh@p0X@MMVni%S zzEJ7{O`m^Qhi`nK@`$g`fzj>$sVfKAvmvlNb)xb-`7@>$PdffDLu$|S++bPJ@#+a~ zwJ%?$;M%^)&+ZrpN=c>D`m=_wOI6dNH7HMuXKq0qAjKnh(egRe)5AvEZ&#ex72^hM ze0GAOxzt_4f(n^2V&>)wbvonP&8Ml#EFj^&5y*OgR?Qk{4J2xg(5hOrJsSR$s+cu~-wT5)GASv)$7))HtnsMQ%QP0(80DR4s9nm z=YqpcG-en=WS;qg)~9v{DL1kbheQrfziaUWx>ey#LqYj(?F3qNW1Bx=`$WaT#GHk4 zdkX4iN1q76>%@hvpm!dFWmHY}0v;FgE2HvoX%p}Hs(_VVee-bhL5S?cQ$tIUymQbl zLt46NPu!I{sZAsNE2JkZH`TFkq^Swjo=pBpRmgzI66DdqbLicG-1kHNa+TvawM3WQ z`>Y&9WSkbp?s@m(U|9~WnkmsNnKK`+okz8fCa0f=7e5kVw0hRGXFVA3*Ca54{)2&g zhx(G-67=?#I_8v{gn?~`ZYtCaOdR%X{HdlC_gaY$Ww6oG^6;A+9oMppqun5G24j}G zNUY=5b5Ph;Wi)%-y4!AX-#Y0(@@ z0^&j2QSnHyd6aeeTM0KtSvMMwN*>SU_;n5ZcO{1C9S5?Csg=M&n2z)?L|8t0dxV4s z@+<{Y52@&qo$d8f+c+cfsgLz3H)32}YM*t~@&4FN#&mM#BYehE4`uYl+jG8Tnf!u{ zZYX+Aq0Ls&?VqLDnnk-$@9_jqA}qG)FHfyqq4}H8;H#zLa=h?#^3MaJ+ayfvuj?*S zuLv7cpYzOdfnG!w9=_p9rzjsfyJtb0*k3uD|*UO4)aRR>Yb z6r&w7)&tTbFU5Ot792r+DR>w4C-q7MzEW!@*f~fZdq*-?9&3^-Lkx#TSX5u-YJ2<^ zz6X?v8KSYNE$)#)D+uJq5PuG5*6z3Z91scG;^;kWo&HV#FmHiTX1yTXQ%6#*QGf4O z+-E^1#WYgoo(oWpe;NJ;*0~gdm19O3u0`5u9iF~2zclfs7GH@Pd5b;xihM3OkX_au znsmKRU2ET-ryo(5Y*2gvzIz3ikRDCn;7=+tlFu2qilBP7Rr^US&i~-B(bdgN`@x^# zj%HGQmrz;JPgPWx++&_K%(Jc32sFMdQHUsd`E7UQ@%A^KPZfiWh7i+Ftk{qqW~4T+ z5qHYeA2Lk8Ka4Sk(#)7rgRs#V%}OpCubdxH+}*cph61*{zw~b^@JTik=;Obechm7d z*lD-+OTHEfB%eKAw-r6Z(`he(Zm(QXAPyblTCpuUF_g@70-N*M+avrNsLl?)KH0}9 ze3Ms>a@JrH-iQc9*?98>jO4fU=u~Uy;6lMVk&%j_FqAIFru^VX)LI+vDND&^g z8-1K{vh}MbP?wc&EXMzKZ}n2>&c5g zqu2^jQd`iDi?uKO$1sOkIQ7a?&maZ)-l?v{)V$k|15Kh%mXH^MsShdRifh(OB;Var zNfK9nOwfsEKp$;MrN#aD5z5TDzS~*6%P4i#m4m}6sQb|@A1%iA$>RS$IUbL_&YhzF zSXv4n2Ah}O884G&>oY{fYqohgbyLw9Q@3+Kaam_uhF){%Piu{r_xgpNeAwKwa~mkV zN7A9+LBpSO(pd9%-|T`;Nshbmi7aWGfMK& z_8Hy~Z#sgt#J&Cf_TM{t2-${M3a(XQ@HJ z3b_(EVoA0uIJ39T>7uFsNH7Gw7wF~Kw7PZb{Ti6P5mrvHY;iD>awE2FpQG3`G-fs3 zICVO3)c#umNCUkN9XUETBNgC%afQ-6nb~9?bD`hzY{6+q~37yo(V(4te>LA zAkntfLpN+D6x5KMDUqP~WpFc{cv>4TXk*QnEd5k`wfElNAgB=y>>bg*ix(^Z(GwMX zu%r{(BXD@oIJQUL3}e-}A(af(G0hMwYgTe;A_`p|DerHJyT5P+fb(j4A$Y z&-?A0J4O^EVhuwxd!e#UP`tumpF(POxn)?qBE0TbyrWXl2*S)zcY3_MwBSJatiudNeewU3%IhP--<( zc620s^%|e%9~9+Qd@oZqCCd@)bTu{-`l!!ciC$g4(A2|BtrsVAhAl5p9?2asejW2H z5jw&?sgB9l1udioO1mr)jcTH9aqc&BHekH{ha`5Q=f-#uQu$(!;}bX83$`-vhc?fi zVWHNyXEM^JF9Gx_Y&TWBT zMpK<9=pR}98JM^n=rYTud`?A@K z;e6puqDeyei#{3`;ZykA-XmWsw*z#h3n zk`4ZRQ}pxS=5|TaLZPyO`BpwN4Vc}0Uum~yaGN~Y)nkrfNE{z6TEiZ$`eDHZIk$R~Z)jOIwYWOUnb&c183V+^KPCujn5RwUwlV z8RR^ujO1nbV-;KZUBtV(ey{AS4Plbtuj#O(;nALuWwA;*rZOxSyR#F!rJXV{O?r(e z%wLA6YD-d_@o)dl;NDM0%f$)fO#D)eobu^~2nwpfIfFP2U$m=>?eX95afaZw-?rmvALK*}_VF9JPcaf4t8Wbs!l2m#Z zMWs<#SyH;YL%NNZ25HF!1tb@Vg(dbI-uHKX{K3U8^Guw%&zUpx+~#%1Us~q z#{CuJWs5+)NZd22_h6Tip z++=?l^C!e0R+xmZF%z90*)X@wySUBBBuFN(x-Xj$)`QmFMsXoxlwK3FFX2Z&kz8fA zLKzyZY#UBJ-KME(8P9gzLeo@rsjn`lN(f3kRLgJHB%X3_EUejT?44Se+7_jImrJNK zzPm7sd-!pKY-b>s({+1#aG3z;*o$5U@wmWp;D_k4%!?n2x->FV|S}hnzR;s;I7N*orsw1Pe ztXYz^*w&0eN)=ZkIs?#1pw zhCF+Rm)+a|n|dn5=-lobfso_`73ma~m7dS-gFo-}JZ%lB}vL$e$h22ZIr zIR*H*2RK~VKEnR)ZZYKLIt8(2TFqWFsoQ#)jIXo6qA~QwmIeEJ4|_GJq|?=vMQ^qzQewD zNapSEFltZ`mt$uuUo%;-kBz{Vzeq=${nk8tu^jSk%GvKx!m_uwo;^~8-L*3qyn+IE z?d}f^I$%cUrg9bv?vPJsx%kU~C~UxH>qM}AF}D=up#_d9A`9AYG>M&T!KV4p%?HHp zZs*LO_> z)s98xuOqN+2PwwBnp^sJ@7cT?YR%pA#*w#LmKS~kq1t`$G&j0vZh-`%| z+D~VEZu8cVxT6zi}=mf)Usqz!(ruRSubbaJCxPdNp~>JrQO)*)RBSm zfqID^M=SjOQN>NILU2?>5Mx42g8W7V_pj;F=ZdCSZn9>2$~rdU;jz){?E$#H4{txp z@b~d*mf}(O>KAQVhPb8zI=B!>8s*Xu#C^WsurYM5=vM!)!Kv6TU$e5rwVEaeam?2^ z$aia`PV#8PCIts12-rrKINp*NO8I~X4hkn@71Gaw_Td6KmW|MT`$mBVtsrh(_kS+? zZw)=%`Z71OicD^3moZH~_8NBHQZ_9_iGp|9S4}n|ltARXMLQ1;2GGYWGR4-aDI5rI zvD!GJ)penx?CD&h2D}e{{XQDB=sCu&xb#>_=g$Y`UYB0vq8VTtxP4jf?`e>};4{>_ zFel}F@v6)*|1*d)YA##ek*h9EbS+!M`PcE*6;Y3q2ZA^akZn&~#hyI#vqv5-_wUpg zuGCpDOY^v_G#r26k1xsvbnzE=KoBeljyknFeF#>#eIXqlmbc&{-z-mAKNo$|1`_k6 z@nvPPQcM*%0&XbiA?QAm2UxGZ3K&@&usb0Bgk4(}K!N5|Eex z=_6wj@(5Bk`1pEo0MBu0qz4Ch0lh4nklKmW07M#6Gi+~k#=q5 zZCr@BO$g+#2`N86+|wf*kCkMvf?fPrCHH7iJYQZhWiC0nI8x227cpjziD+HxZC}#A zXf`DFACCAOFK!btku<$X1q~^E@l%9ATe2f33q}BYqsQX(R8xp;zN10vd{&%R-Rt`& zQK<9zJ=wj%^Q7VWiP3AwPIlb#SK5i`_+uL8D01BK`&OpVO!2=nEzFsgBvozW`<+S` z@UWj7uEK&H+1jX^=YFt;A zE3`?*dJ1P>`T||hxIAlW$H5`*L2NwozM1*)rJz=rZFa8y`X67+^3R*q>H2~9gW$IZ zQ&N_EwO%aswH#{uJc%Zs+h86EEwM+7;PY1VRMNhRJ$*wR^vc80HST93F*QfnMMUp# zWcc%xmY$y>lo4Vehn0>|Yah1h6qMpK$h+;?BNu@soQBOq(8ABG%y zIag+)i;~ELO}s z6|1%z(o>Q1@o#%ZwU22^(A1cVfhsP{1zI<i={?e4q~cN6d!3N@^LZs$D8TOxZthFw+@&?~g0*YKKF3D{(ud42C`j&+dM z%;u#NwrH^~2SS_K>FoGoBtF4v*29ZUL)1~z8=tt(J(pQ~u&Lm+G@fr0k&=5aeDM!@ z9cA)<`M$mFZapTIdG?(RDmwgKw0uK2L~%dO%XP=|72euwWaT_IC1Ika>XO;*R|f7t zn1$?y2(@RD{zRx)r4oYGk5l);g4PSml_GZcXkEKMCY*HUi&86~><6F+)i20*zDG$3|Bn2H%jWWDz{edp#o%Vn?l9kXri>9uy-l`Cy z#eW;jkCFaVckm^JHMnK`2PG#tRydrN=%7(pOZhdCpe2zKqU0#9ra386_3tQE9fkKB zt=X|!d_T@T$A^!TH}-v+Fin9PLIB-qO}_p}oj4&eyf&}TUL|k#;DxewafK+Wm!^qf7$8 zaB3Ilt}h|zs2jymVuY1hw3XuDtm#m%99M+{w!e+q))uIx;~((QM*Qqls2tb}>^5cDw^US_AcD$r7=g< zI$?7RejWU3EyAC4!3+WggQ@Ov_n7{znn&OBEom*0W9?aJWYY;fHYv3BONm4)1heqo z7)~J%ISYH(jI4Z1HD_#NtVJnfO+EeS(M2;Ve+3v3;i?>hH#j=Qizi!1)=@TCE6aE4 zk)@XW%1sN?fZiH6y)%1dGHjUYkAHQ>JcKYQ8et_FEP(&~?y1>kl|s9~a#m94bb0V; zAh|jO-lb?uYVmtw7zi*9}?z2{b1kZAU)rnee@R=5!($cT|wEuR_PJ} z(DC;JO2OBXI>!7`P?6~V60eb5%%1r0zJH!<_`tB3ZXAPl@XzZnUG>9D6h%6&TONmV z2tVqeyS4J@cKqTKipg|KR00RJgK^`_eF%#LL&w>TnLx}0a(XgC|HAUP2dod;M39E6 z4uUrqOy@xkThI@wYF&rdy$;-1eu~Uvo72#HoFOfciFMnN=j^@BPF;NKj`$gre3lx! z^#`NZ&A{d(V3-5diIXfJEFu~56Ojoik!?~{U+BjWV7?*4Wqc|E13Aujkhb`^^9r5K z@+tSQ&Oq|pPk+5hc?B>uK4;sPyCzDqTyBRc!r$PBhswy$G7w1cg?~pjFOqPVct_?Q zilhSco9j|>#}DY(p$A82-dIK3$EQt={ej>1zjlp=PD@SMq)xHjR}&Q-0uqu4@w~IC zposbXWbSybm2AHG+Avh2N+(`EOs^GP!&q&nafaj&yXlcaBJqn{{4TLL{&-+*E%tMe zxAxZu#En+0a0X2y9Xz&s)Igf!gJbw~V)Uz-FCrfeE*B~%kn|dusAkbQBQ>qfdZ14g z?laWbi`t8^ei@tFl@P53tMT8N(@XA3n2jYin9ub=Sk-D?UwqeqXD`x*(zxYLL&af~ z?4ieJc_tYA=*+)I(h>!mTVY+-9DR(cCiimg-e&$WvB~g zSN}@h92ILCQSprosj}1OWfORxa+9t9F8oN-bHS)`GCkCx3|(TLU7F#-5GAWSc8U?) zn3F)b$_BA7&ffkqwI@gX!?mX~@3w>8_P=TZ(KpXo5Scr-1yL=9tCN`1Gm1u4p!C;H zuvH?1r#xD-cG=)c;8#$^6ZVOzjLX#m9!!lKN16ZP%R33e<#3wg+tgTfL+`%^;;bID zqCO9t6BJyjh86`MLj#_S#Rdig$tN*n}}F^RMVU4Ei!sx-`^|^ zT74-S06|zrtlmo?ycmngc@&x;fS~SP<;a*HzX9`cxrg|$W6o6)U#3WEb4gQNGUR50 z(BOI2Y2uMka;+bWDPvEY2q8cUi!dh6%Di%Di%(u0SUbp*} zHiR`zP}Z~B?MdK`lKp6Y`E#epGgQD=O`MhY@x{rvV?OM)bR{N_*8V;yswJY(AguVv zXvqh%a#J(-GD&pJ3N_)&QmlC&9>}5C!~jp|iAp_>vD8%)^^~6%S5R6vp04!}ICqwF z+w1zB`I38?TYoohf~o>evl~pRKjpN3hG6IpjjMhh*Ln^q5fC?s`w4J4kN0_VYo>ug z17n^=PH&bUJJUvX+lm0B*u>AEiI#hl<(f5&uzr|(iuIIJZj`M$Kd+n7y__+GkN?TR zo3J|sXQ1+XBtTslkxufV7Y7Xr1zKF;f9aPiNlu|v@>xV0%T6M_{k}V7!LRvM>SpDb zWdR^k+ggb-;f#yFC=DqgIXN-R6KaIFHgj?n+cJmS@97dHKzyyh3`SG4zY~FdTEK0Z zsL`G;WQX*r-NtNgkL(n8Ywd{ z9Y3~D6)jTq=Dfl-JY$zZhL{A-I8NnIc}f;QunZ~@%feaxIR8ef&inZt!xE#n>F4r?fPzI zSM)(|x24g97yFUpHZN9}CGpHx3k6KK2_97eA!+c0a@JJ~d5*Xn_R~$cciQL*S4il|%7a_Rj@&MG9o+L`@&GUBI>mpi&E! zpDtz)XJlZ-R{4*)o0qZl5fhxGKiP*DE0}(r5r6~~dG-COcMOagDTJ6_o9+Q_+e2Fx zG0}7RrmWYdEhx~-uVRB&A_pzXT(!s_U0jBLmxn(76~1;xCq}tN!%fy5sf?bEBT`+a zW3A8s^W4fA*HT0mYu?=lzo+-0DjL_J?xcdotp`!*P9$%%U3^I8kxCLMLpCA*UY zGNa%{#`SK#^-MT^{gN@()S;vDH~}OF>0HbHGnj+MhMdh7ANrKOSe~S+e)T$~*ktJ@ zVTsyT{6x?spDHFU(r%s{Sb(RBVh5w{3uXa6ByMxlm-auXBP^@lM*VM?|Aw!IsY-W= znX^k)xy!SH;Z-tbbP%n7sWI>$Wjj9bOElkR?Z@uNQdjif@76pGzUYqFHWlfe%lkTA z4db?#A1BU|^TnH;X0A1j0X2na87Z>@ox~Mo^|T0uZ57aI z8HVI|j?8D&jZV3}4-RJ1H*sPz0}Y>^O(-_mK0QM!1u$d=k(jm3z6ls_1&$=Ow+KaR zED$t=5m=9eT;{1Rn&hwr{;-=GqOKGPi9MAeIh`7?{_s1J3LJ9x4mX`~zF)J4p?bX6 z&kv_Dhh;90gUmf40y9sBf{TN?Y9fq()!N&hXiisOgJxRqjN^6U>3>a^TCd76( zEQi)bLy|od{?0+^@WUwYuz^M^Xk^kICn!#||!Z zKSYZkc@xbiwLhtazG)H?=^#-Gh&`9=javSAx7ye9jD|yo&?AG2K7F41O4d?DjQ90) zmfmVuZ_F^HxJABwG)Tpr;$84BU}mUxYx!&-;@8%G990wxsWhpO6SXV#<8T@`;pDy~ zVBtjG-0c7IFQMpWqr_(y1Dg|!V3SYu|D-(J1rTRUcQUnF?cuts6HF(Tu0*|Sl|FZn zuCGeOE_2j?i{?)k_ z-FJ5RHT2U&MY73ePC*ek44r|+*X*m}hX@Q%Oz{Ze@aTU*A`h?dTnHwOk^@SB$Iyel z@>x9S^2ghR`1Qi-_#BDivWWJ?A!Qxo>tmO_r`N^!`_ugE!E`!Nxn`mc_C|X8eNR2_ zQKGkIJ7sj)8Nc7h`v2ExOt=6od2C>HV=0)_3@@yZqf89pPLZR9NmT_Dt~}2zEtGpc zThrO>wxOB%Pyt&)PB8G@%1iv)vg^u5b^P=B$k8Tj%u@FwYf6O#BU3ZNr6#^kssJ7^ zaSmBPNz?@vLpg-3>ZJ^-@pU){#yG<%)BRXMGX*ixw4Xe?mD?I z33b)w2GdBVt;wOSfi^MpQbN2`Qu=JaI%s0e9Q@`{ESutj*yiKhQMKa_*rLmMHA1H0 zw``6MUr4X88}_Hr`~CnN`<6{4L|wvesL;!@k&z#n@r0T|T{PQ&ro!t|HU*v(Z=HH5 z7_raYTT#%zIz;7_=2z!7$E^MGm+=!+#^U|>huvS=|3YPEZ%zq;T1&ja()%jEp1AN4 zxeU3(1G3ogHv)#lP;EO~PJ~N-X>gTS+P`;F3YE;`@C{?PW$%EU_@_hPy0{;#cRol$~o}1EKw#R{CX|?f@ z=;(tUdGI~N*MpQF)siT;9`U_8?B);A_4hqs*9o-5@9F_FxOvw(>nV-t3d`D~2pA*q zc&!rBA7-QP*sRxdj{%C_;dD|oR%Izcfw`-G ze-`@Xsz}cV6j)A2KYYqp`BhESfhA5aeuoPmL?#1=mo>V5inU6j3(16NbwCTT3r6stZZh2|9}!&D5Kvq&;R>JJ_8W()i;oWV&WN# g4fX$h@a4sG4rpIExqXj3xCVZ-)b-UWRczn?KbqRyX#fBK diff --git a/test/visual/mpl/graph/references/7_qubit_gate_map.png b/test/visual/mpl/graph/references/7_qubit_gate_map.png index 1413da0a7c4733ef0c4c38d3d1dc9b1b36bca548..4a0ed4fe2d51bfebe8f1e493bddf9b5fe9585908 100644 GIT binary patch literal 9122 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 literal 12001 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 Cz7iq; delta 46 zcmbQejb-*WmI)qmhB^uvB_##LR{Hw6i6sR&`6W4-NqYH3>H4?1INBT2wx%&|l>z{e Cnh^{D diff --git a/test/visual/mpl/graph/references/bloch_multivector_figsize_improvements.png b/test/visual/mpl/graph/references/bloch_multivector_figsize_improvements.png index 80e73131a39b8b9a211f4d04187c426c7bd74963..5f5ba75d9428d1940aa8f3157c4aa819e3ef9841 100644 GIT binary patch delta 43901 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

Gz- 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�JZv&`1e^x+4r~%GuzAknJYpw2R|NyPidmr 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 WrP^;7ot|I-A0>J9ca^ec!T$@|8}cat literal 136101 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 z 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 z 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 delta 41 wcmexu_}g%Thn%5~LPkkRL9vy-er{q(K~8>2PG*u`eo?yqZ7z=XjcHRQ08ZKutN;K2 diff --git a/test/visual/mpl/graph/references/histogram.png b/test/visual/mpl/graph/references/histogram.png index 3fa51ec644ed42d104da395a1129123f0a5035e5..8167908c1ba30af8f5638acda9b50aa8c29ae1b0 100644 GIT binary patch literal 10300 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 Nyrp_G_lEhO{|h7^yTkwh literal 10759 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 diff --git a/test/visual/mpl/graph/references/histogram_color.png b/test/visual/mpl/graph/references/histogram_color.png index 34f7d449616ad7c824ef8c54f44797453935c8a2..57a1cbabc1c0cd365d16a0695589b718ae9533ca 100644 GIT binary patch literal 10353 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 literal 9576 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 diff --git a/test/visual/mpl/graph/references/histogram_desc_value_sort.png b/test/visual/mpl/graph/references/histogram_desc_value_sort.png index b119ae2deed4c439943ca252494b4c26c48b69a3..71f87047479ae081cc09198447821b7bc741c18a 100644 GIT binary patch literal 18290 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 lPi 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 P5+f(0bR*-M$>aY3AP@s+ literal 11864 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 diff --git a/test/visual/mpl/graph/references/histogram_legend.png b/test/visual/mpl/graph/references/histogram_legend.png index 77fbe9c5dc0f947fe9c8bdfea9211fddaa6c4a8d..0cb218e12528289c8071de0edb60be94c30877b9 100644 GIT binary patch literal 14197 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 literal 12162 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 B8an_0 diff --git a/test/visual/mpl/graph/references/histogram_title.png b/test/visual/mpl/graph/references/histogram_title.png index c4c6859c8f2eed7af9ea8bd0cdf9a717572a2017..84e486d45e483c5135f74c9e6c934f068a6e42c6 100644 GIT binary patch literal 12343 zcmdUV2UJt(+U^DsR77-CP(*M>5Jd!3ilPB480oz?kuJT5>Ntvkh=PCu0xF$AsL~0F zih_uADWQmnB+?0?hWmbV&Oi6uf1SJ5U3c9w|5`HwNp|+$-~Qg`eaaiAp{B&Og>MUn zVO;ntm$Wd9H3Y+0hBmRoE7Gm~-{8k-&&vj$+AcPpK9=s*n5w0x>kSvr8}`=@cw4)B z*tFMerCn4eV*9XL1+-)Uhl9LVLOE$Y+G4#MNZcFq(OO`^WJ%&l7 z;V+%n@lBeb_?vWi)i%s9K8A$2@7(q3+i$($HW|ZuKN7+p{bnufC)(^^m8f(yJ;JbI zSCeN|&&ww?ygrTiMzN~rL-lBl6+tRO>ZpK?U(c@Hss}dyVfjfg&m#f5yfNt1VE5e2 z(2Q&CoYnWai#EP9iJUU=O{2fS1>LhOBft+#N{n?ohSf>39l)><%T4FtrTXn5@b8^p zF%}HldJ$vAuswG$HVl*8%CZT=EcX1J4LksW1t@e?P9-ru|r1zm{$HK3-n^kx{2F1?OcFRi~=wJ_(yPjJIb>2QGWU zi^I|492nnG*6nq|GYp2lo}OMTJ#wEcHD!G@b9Hr9>@jtnOHkfKSXekbGBS@omLwl& z^yJACSWVJpjI~^71IIQUHMRSqqM~QJii?UKJ${_^{{5ARLn~qR!w<-0@(r29bPtoe zjg41hdB)_m6vP=02U_lk?1KcqtyQ?B?cHIq|YD z$3)HEKKsIj3-c?3>$PfQxs#_uQUYefmKjqdo?}Lb4;(n>)c3OU@o_65{K~?Fc2nFj zVLV*iWN1aEddeho)r;1Ztxqy@=psJ3aPgv7pHta*E~z%how85nh6ZDjGCDOy@}B6m zXRaXsKXkK&i{18I#GRwr6s;gt2WMv!Y{|xC`9W z)vH(Aj9qHdJ34gmZQ;9*>KGVgRZZ0zld5OK{f!fwGyJD&^jmO@B(mqfhbARpuGyidC|w|U)$R73I}U@jfy)gF z%wO^7#qZ6DnQkNR#_yk*{5 zai;v*y!P9-Z}HLcD?d+i?U6jEsj1oc@#CZR@s4|YPxiYlDbu?0+WTC{d7F10%DNoE zGugB>BDkJ){uaCamjX*UkMH-2ii@SMzu$h$_@#=yy}dyEOskUMIC*`AEFHA!i*F+u z7JD`wEBjH{Akgkes>ujmX9Rb{9!MQa_E)odcdxb5i}q=S&N`HCg1PR1XZ$VtTW@V( z6|Ga>+-u{;jTLGs@)PbACi%Z!yi>lsFhN7VfB9mdZ)B9PGB-OrYZ7fT_q}G-4qJ25Y-M$>#niisB7N=6CPr^w*#Om{w(|qAv$EdT$Xhq= ziXv^s=BBqxhA1z%tS`8T9y!ulWZk4=VnVcTiqrL5WDw2QsQQ)6Wm@U=55F*a!*+_4 zTzk8PYo82JucfmJUZ)R-3hFKS4&Ubev{Lcx*|X?0I5NAsy4w59qC_aSpq{gHzG5Wb zsM~yza=duuct&DLz>+&Y8lGr^w4>+BL|HD>$mB$Cnah;?)n(-xe}*1x=o}&k8(aDM zT0OTyRzZPA4T0X4nG$4V-50dBToJ{8RUz=H&=DNY^!)krx?SY8g}&aOGML1hi*=Z| zArxV3bo6r~QS2!|g<7Vz&w!t8WM9;t;}>=wQu)kWTiLyDUv5$oe{6ib{ zWntm;#>%LcrKvUoV=`}k-qYH~#^F=aX(*y7XY!gi*M7PAYLdYKIhZVzeKB;K?kC!p z!WVjZM(Ns_YS~#?R{){V?vI_wF^)-l>C~rJRePi71a9u*$;RepT|>hs{xy{v_rtxCKsXR`F3N?eBt9k9(^Ptt41_GIxu)2C>&`>aN{vkUT zpHOgcaLq!mqfu=@h5YLDMYs9iPdYkg?Ybu*C3wGA+=bo02+&^=@tgjRv z2%jJmcT`Lam5@=<^{|DhK~i&~Z1?gHbJL39JNu+OzN-Yzeh@+Lc~1@G{rq_Y-zjJs z^DRi?6+C;IT~a)%N6exV;cKBYsb#j;ymT3qKW184(iP8wbq=3~3;Ou};X%h5 zCn)dN_4TnaF)si*p+GxEuCGr;$_{)+AaZ81{32klwwqg_S@4?IMh=du4dT!np2~T( z4Kf#Gp@zs>1_qDid?tyXo}QsCjiu;2IOIe}M@xDCG+^}A{qe^izSa6efQF?6x&!@Z zkM_vB$QY;*)GXkLqq4GPdc_&(>Er3~W^ExX8>BpcXza%kbUemB=|bZvg`b2)Dkiy6 z31cyMj*mH1Nz1Pi%04g1oS;;dRr*Zj!z02i4&5S5R*ZR$#_BszD!l|G-WU{E+{`ck zxePMC<>wP+T^1Hs-@Lh$XHa+n?S+nP z?NZm_3(b#@UtC+J$B@avc{ZwQYF)2ybH=8mkN_&EfLLvU%xMmaTf=^@mCGy^{D~2^ zEE@{mr{QDzZ+a|P>bv*=0ysh=>@Bv9>U@Do?)mcuN=kHs*J$Rk$;p$YGx}OuU)=~T z$vCuwm*>Z=n$Ka=5@$KKpSvYTn9u4W8oq!ES89k7?7qm2yH3ACKO`@2_ChgID6`hzUE5;fB4tsB)zG_)8(Ui9 zQ&Ljk@y!1$ZlN|FC6y4Qusb8L9e}i?I<>e;g zyLovLz7_Q~pXE`+%zlRgKO!gBOFa&R@bW3&=~URcR`fk_2QZ2A8X6DMQfhDhe(Tn; zWFW^Kikg}apTBrPQD{)T1cw%Luds7)?1Yn>*r)_8$35W=7H#wIz*%Xh5AI<;FYaU=Z{075@;!m;O<@`Q2mI-{tFG)Vvwk5f-si}RgMS%nm zX5U}#Ms0l&3XPt)XE%oF+``^$Ebh5MZA({yzPno=xJEDFlh6?n5vAz)p^KjHzdWW_^CQuSHU<>16BFP%XHqBxQATmrg39!Bs4vUP`ZO>2zfX`f9gsu;m zk9&FK*fCulokzPzSg;U>?IGntOG``8@ic)_AjW`igJPq~2fq#9?JoDUax~7E$hQN- zR)23Eb*~@_e07I|(;ht7zMF@KZ%*+u0C6{5Q!LO;_>~6N@EOqv_&wLE;eI7GCl}oh zVih}f?BJ7iP7=y4FaPrO0}Hko7N$TB4jY5};D-|4yLWF6k@$$>+`U`hTudQldC1Qxdw1z>sE-|jdEMe<)m=DfR$CE@&Ef=)Q3mh{7n2K^p>Z)jL! z47yMrz-@57X`r%D`xYkp5QXxB2GZz9UYl@{wtBafF`fa$?VBBZEN+^5Fhqg5_~H)N zzKm}3U{gRzl6w&B!`*xLjx#rH+xF7pDoDUPqn#|LfQ+W6ryl{*(K{CpWFHtv7Jzud z3F~lRn3TGmpb4eUk^(oKI&;Q2C1^PtI+NMN65<_D5=Ldtc~8&yILvDrlhQ_2Th~yq%-{6dL|Ye zx?3ebF$eLyjCJVzIPr_o0Rcgk_OR7E94Ju6KwhC3CZ!Xb4+#pU@O3*b3*<&j;TFOI zucdquaTye8_p` zAgv4vNw*8id?JWxp`vmRD0c?j4Yls(hDj&r&8dIR?Dz5Izw9CRw5aDsQQritX|DSp6VM8`Y~9+?7<;sn z9K7xzQC4{{q_wqG^zdOX%-7}$^5@*~_P#v`LqSrLY7pni< zx#F4c<Pz9p(a})>+UCuh!-2IgI`T{2I!I$6z3AstY6-b9v z6AnvBby(Ht=IQ}`a7o?VYJfZ*-L|RK5?Qg;hE)L&c~Jj|V8@d6^PGRSgU=z z2=7ho|C-S?Q;57a@iXlgiOF?a+d1=+>m1$K{y+4?zp=A-Q_*gq+7CEg1aQpV{QN|C z)WGIn2L^%3g|HAt9EuXF7=Oz~@b+_U($rwk=)v_n(>nAd+(U^l8H~igzLi#bfvc zDf{Sw;Pt@KZ{O@d;~*u*&Mk0brsEtPEC3QzqzMqfE(E3N%Dm88Rgv)|lns1!nVL(Q z2Sg@&ZOHgAo#) z26j<4P&4$FbNMj)QAKu#`T2Hr|D?%5G8x+BKp?{uxVox&&{Fz|6DQ`U>$#PqU%!6+ zC@wBzBPY*~+Lg)TYuD>&u&wOAK|=+n$&1y_q!ar#{==d5&%iD*ls+^>-*hhZA#})iK)z9+ z>EQ90Pt~sE%Xv}LR#yY0?b|MayCTq6=FoW+cx%^I&ZLIHb*2xjKm0ka9=sfrp`MZt zrqejsW3fVS-@PN;m;!eZo38!}kJu+qvYjcFhBzJzF+iM1otQ(a9kqe}U_64CX;}F^!Eqj3KFx;@ zA0pFDE&1$t;o8H4O1t*%wQnw{^J8OY&w;jI$r$i2wQk};#vpJNaQxzhCI-oaRx537 zT0jj9(Uq}oFIUmg(*qK$5*8LVOQ(0jI#9*{d&hwhfMZ$YdLeZINH9>HeJfO{e2ihv|;hkKZR%_;E%dM?6L_#$ZTBF#@uDnaiJzkBy{x!cIDJ$v3C4Y^6U z1Pk-I^@S3$=l0777yt&M;zE{CqH`raTFUklKa@y%W@awj+u91F8_WV5wAGRE4DIv7 zxM!nH@ewI09gr_=BT)+Cctkh|bZWYifZrwXq2Z*+|9z{yVW9atSdDtzZWZ8kqubfS z$q6-VG8Qiga0`zeXD@;-=ldnn+^f@+XZ^Bvmi6&H(u7l5`ZfP%vf zTq%PV%Ui4rUlz}$%sLGoYRr85-1^s%5ox!tmvHl+FTz<*@dFA}fcxbAs=GBqbzgHb z&KP8VI_#nW-w`f~cc0TTXnW62U48quH2gAD=p*oUK;Ef7mOKwVy9-Px3BPqX3*Sj) zR!JF|uC*xyAjW0R0*+q8U`^3a;lKq0j;{`{=_blJm4F)p{QJo1(>*vPKm_p7^q9$@ zji(*r$eXTzd;bv0=^C@p_Hi9=@0V&%<U#Yfa(^Nl+^eSxByoBpW#B<%nW*W zV`F1~Cir7Qc&IJFt9T*Uou~P?oqnpOtEX34hO08u)Eu7ak_A7^yQ-$wOX^^ zlRi^pE7!DP`c2r*O7Lh);n{lBiVVGFvk2X`|50LM?(5eV{)}BtyQcv`^ldHv^e^fl z50ur_XjFlD#(39W72! zGubovI20Ya)mFAV8INKRB?%n?emFkopq0{G|eZ%)BOnCy}ERC4fvQ zu<-k7UVi?l)~TJjxXDHE*K#3qIc8qlZ#8*y14m9;+9g^y$%nMGxOn*3F;z$f1fq6H zy$mGSMU48;6u*qQK>3~W?<3OscD69$Z{+t@@ASa&Njp3m2$)kvmJRSZ9oRAbEiG;d&gwk4=h^B9*85`8b@HaCy-GFK%LncDjH>fo$yw=Z2R9ByN3hUGYP#^fZyAJ#fnxQ}lP~W@-Qiw^;3#BNBH+Of)1uPaoO4k9D0eyii#WP08{x9Cj z@I8q1xeH*J8W4(G>|8l>j6vga*WuGG3?`1OS{dCM|Pf2y0@pbt{uwKSFmY=Ye$wQAR$1qQMGR&kA#`Y=u!v(woGCq3UaeH z#BmHgzZ`+w5UlPn`~fy{-ar3XKV|`!BPG@pg)vvv%aYVpR8(+kAowlVn>I*_i|6aP zusRj@ERHn8$GqxhG5+J%E|szvKvvhHux>IK$asn(it_UEJA&Kb>p5XXB6ub8XU@hq zrGw+A2?1We-{6 zb#+Hgcv#APrp(MhV_+IeV!_)iRAFP#!3lAMra%BH)&b%)R|(#p-V(==N^w>g>#GBw zQ`%*~M51=_+6J|a&`4^ak?eD+F6_lh`X&$%2Z5RE2x=CJs=z`HPCjMjhdF;Kctr(= z4ZG)VSiK1r4fAT41qY=Jtgq4U-;t_#_39NBDx9$J)1GdCt~p(kZ3wA0=(;FScsSqA zsqjf&Vj4W!4p{C-j~-ngy^B6rKa2I(_?J1?F4>?I2<-?+>mc|#4D8Ag3~QqrLMak6 zp#O3pz|o5WZ_%{}TAJ<0$InjMezIGd9p#g>2x;((5m85cRNC(I0c3Xf^z`tkZic(W zi3RU?4_=QaP$|7IaxweXJ*j7=sLW}1d z$6*1!BZ^u)oaazHi46Jw-iA@230p5g&MODJ3*4up$BuQD*teGitr1Y~;!%Y$fgw|L z0mz0&G1JP=;sk}@+We|Xxl-VWK;TuK@Po9N4@W3rPKPQS78CpU`UvdX>d;Y^!}w!HC7;civ%JkI3g+g)Yo#j^ zH-&_Rz~k+v&Y+tNw`Ms7jSyJ?DEWRr2Lukn(uslZAD^5gKuEM3WCJ|2{v1v8o#Da~ ztcGA4BonAdAY(|G+hh*h5`mLQN&xT&R6Gac*oIJC1U=aC^&gwZDBi1!Gr)J+;Suv$ zoPe`V+2S!2c0t>Gn36K+S4N+k(+2u2<1)~X#h@Bh0B-R4*+rn7B>Dmh>4)n>X>Py4 zu^tA$gm_n(0=AV7)K*uUcvp>183Lh!waL!u$}^@#NYrN07t8}@ZbLK@PDp~auH%nm zvmlw(lsHr5VDMq8x^J?tOdW;MkO3L2--0vlsf)(=6@sdPrFy}R$Vp92eK&!K9wfzC z&!1lawc}W~87)D)unSw@L}|Cf*EeB=rP26KV3?HP^)+f=841|fLHsg!8>QY8Mr&ii z%uMKW89-Z2{U=KG?x9EMCAOk`0E+GT>e?C|^pGPgbi!$mjD{t^A86gcfm=_uoV99w z1UEa-P=uBA+#oFU*h)jz1P}9yVDM_;?A)9%9>_Zi-65V$hZzJzX;_>P{UR}}1w7^b zN{etb-*%ULj=%dr%HLD3Fo4@g)_)RfN4Da0%a^*g_eZjVu5O1=RLP5f>GW76KDE7dCk`*t?^y zr@nd0K@vSau<(;``SNXG!~PV=Yn;pUtG4;ZfMty2!)F>N&oc1sC&MSOKUu~02DS|*Hh??p^}Tc|g*Jkld9(AX zs%j^&D~Ed|DEcEOPZl>W1FHfo)5dH4Z&<%xrMc%`6aZoY3j(5T$iXe30}}=-)&I*3 zuIt}3I22a-*Az~~yz-$ma zQ7e&mG?~|Lrd5)0PfxjB06z{aG|%-_87{IYQyIcbqY}GkkWy#7!{+DaVp3AfW4+AH z&4Hj1h^P7QJ46X3uf5Xh^QtpmU6r|3)@NO&AIN2-T9#N@iCdfXCLE_pHxGPS*gVZ% zy4KU!($6_oN@A_mSYI7e@LFATL;4#BfO4*8wwH}L(;!F($ycr(%%J$7fdvTpkof^d z0L(&MR#bEVqKYC^WCPHr1_xhf1C~)!y4i;SxSxY=tW>wXe*H?c;(h*XB;sHIg#bj) zbM_m))R|%=I~Y)$9JD;{Aovw3VEPbLK;ZIxYlYchkwa$=dlCd&sWU_WCR;^x>c7HV z+}{U={?5~b|7TXoDgXl;8->iXz~8~;Cqaid#KF|%xtbGl*!n^l`3Sh$5WTg-*iepR zeuW~kUw}2{2|%Y$9oVx!M51OsI%uVD&;fWU(4!b8ltr$6d&Y8;IrADF2?qK*KwzRf zOj99|4sF$qgzOxcAwii@klKGpYEDj0VZ4Z1l7^pO#mb4l(l(rU->@s{{4je}GwFH? z5IEPABzDGB_DqC_Xi>!{@(yvsrI`_s5wkNhnjojaR9vYprb$zrsb3f1G za@9o~huJXe>(|TGVH}eR>U|40cYL!=vFiyF;`8UfT~<<}fpG*X^d*5Gi)WdX6%PjL z0Z}}V*wW4y2JgOLH(>Y&R^mSY>92)B-`?*40MT1H4daZ!Jmw5Ixw!I3J6c1)hpsrt z;d;J&u)O*S;oFp$l{p*OF*}jX2pV*<6oxADOsn)D^y5(jgwP=0!?7O5LuAeemH`@T zfiV{~3G!+Ya#P^(8vi4CIxdGzRno*EVNp@X(I3G%(WFqGNkvg3=f$BKNYA94dP_vP zCpMf@EguY#EvQfl;*x^Kdh=f3wgd1pd(%1C0RKL}W~PHOf%b@oII?^c$=nBEA~F@` zYibt1Mxdc5G%uPsxT*-|Ckj0q27TEvU*Q3c?TY)r9Ft#P^#DIi6g)_1V#w6?oE|za zEF@$Hvn>$!6%bUgNEJLj419NxW#x8k2kyZH0+^0j-13X(05si5D4|2+T|8n2smMbC za|LbT(t1`q9W&(Tw_z* zg8&`HNYKh2)(?M%{^m6N2;)lx_Z0b_FyT>#q|*`Y3_H+GXygVQNFhApFJB6+pb3gc zWNyr9*l})8E;u7){q7O)ehCZ-!-mlH`!uL5QIiJWh33UTIHeX=fKk-}4;eT6{vd&t zSBBc1xe7Iw2)*5zp=B%-v>E?5M{myT3;DN(|;iR zI_@3}ksQc3twM1C4aBZK450Jwkd%b066bn<8LPH2&p5Z84tjVcJTgo!p zAyhjO-y{r402&!UF*@Y`PIQBFk&p=RA-}cH?+#lCC!yKp6KbQZ`;DZ1woK) z8W+wQAP8$9g0S>*Y=SegKf4Cuhl2aLOYVj)H{HFi+_`~hUva;E%fv6U9L8VZ1iY`%TL%nd=fuAqNeGO+3P2y*zA z#@W+G-ft$l{V%n6RIJZXz6S=1X9y=r-p|O6c8qa8=PaQqZjff5ZZcPtFBhj&8{6&N z6)GOlUeq0@?3kBsp6ht-lwz!Jo8Gsw@hCy3X9XSQEyiwIhACCMT%(rP*6gBf*bYlf zr{2X1QNDP5w5|AFURlMdTjBPg)>S|qhIOo(wg5j6J4-fU1PMI;zyBEcw&+&-iMvXI z`<1-O6Z%NPH(`Xu@^#(YS#Kpq&pNZmAzd*vd2sMLT+;2{tWEd)keQiT7~eD85IZ#E zJzpnDv~0TZM#bNJZn&WtPD+pZAqklW;2~inBX&c>!zLC110izriMLnCvJir%WApui>^`1TyaS|TcP{yDiWT+$e>y`d~8XUb&I4Gj#!v|jmt zq0Wh8Fy?~z+ExXrv&Z(dM4zTXwPYF| z)L`clH0msJI;a7oODy|9ZHVP#tcL898)MLjlpB#&X(qYmqY)O)KW)|-6o*LC-MO3e zsUDl3KYxxjr9O)|VwQAwZrJ#lKE5{DzB$c)d3LC@|Ec6IUf$F~M~Y@xym$X*E3a;k zr+B>S#f#4wbeidaRaZFm-JKy#`gptH@#Dueb#*C|-DL+gv?7k^Q}V2M_wUdB_<(&b z>OxfsM=?7xJrNNTlQlo@o_p!t88b7puoPLxwv3dNvtC`U!8j((Cb)?1tyDVqLy^8T zfX^-|x#ZMQusLplid{ELO-)6A(dZkEtF$?H?p$k|mZs*9l@GO{`;A zI50Fbi(Z?)z>9Y)>C+t^4sK?~b5L#d6vj zHDFDBvC9oFYTx(iVd-dEtb33D;%K`qp|x_gzH(%)5lb1sWAic%(;WtCLa0n177oMh zh-FZ!RwO3u4XiV!a=F3fO~g?POu8xoqN;n21QVt3a)WhKB3={CqV+v2CNE zdRV^qOuqzG?#|!^Fv}o(Jx;N>!``1U@4AzRCyqx;{UIVDAyGhpmqA##iYmZJb?oi! z?fe(U+l?y@A>(~gmyyVE!rCao$iyVAHQSUn`0bTB$;YFxEI`tKv8<<6mSUMaR391K z_Vn4a!kZ2JAwt*+9eiuqaE#+TM7OE0Z~qf92!>qq!Z6WXYmzyxveH>`iAz0HK>x~> z#6!CAmO~>qrhbz=s<+7<#$s*4c5$$wArQhZtGOTJ&f!FX7$@sDx$w)_z3^EWH*-=x zbm-9h8kG=`7Z$eD3Ubtk8t0Yer070ECcji0%_hDQ4cUA0{85XdoT9bjN@lK9**0NL zSH5F`T5Uy67B_C*lmIY*buxjt`StFaV>hn<^OKlUPBGi}V^Ux#axFg?Kq&JZx|q>C zgy!Mj(+lad%y;&f6Z*7TCk`_cbON_ zvtuaICeMS`HVXMKarCG$L~*I-gt=2$Oq*z?8})~59uejOuQdC3%hs*N*4BdNMDf>( z9%DvB10^N$8U}an+zFu(0@m(^L~a&db!FS3O4=jm{H86(EV*ZGp}4NDZp(iA>~H(M zx)Q&B{Yuua>RDe~9P6nJ2)Sb1BVi+U8{h{0B9-Mq9_=`cF+g8)qz$gUH_|4SC^VWq zKOF1gF!=T5)6mei{6>}R)m1;z8iU3U?+~cXEFv{hvuDa3Er_E^$S+ldHG?l%9UnoV zwJuC_I+9k34Ps9@y^f2^g_Wm~6V*COJsjikYps!vM3TwY-ABlsE|q_N_kc@9&)PaZ zB?h0Tv4s@T8?Wq}6}RwHT?mr%bflGMG(%~dQ$%W3{7*8lKNTog8(Hs>I{+~Y9a^(61a_n)s1`;f_v(;# z)?870dplq+1!_%rczEjP&!0EF8DICE`NBsZ&u?^?ANd30I`K-G)OcT=ckkXM20nZ8 zM87d!nI4Q?J>A2c^lDAh-UpDRMe?CH5pi@$6abZ#QBXG>xpBF_zdx(oq__O;oROYh z0?UR?Ba>xQX!N?^=KkFF@Zm#`7+FO{3teUU>qlHdd9DLBqY&EW1$HkX?y{`PJY}m) z*#mh6SlD`>-fV~&UFdX)OgT?l@ggUjhPbH&T%31VUvTkRovCfjwUBe_DtTAOb37hG z(4VT<^YeT3NqV)=+Ohfm`snCr^D@ue{(%8HS&eJ-iC8?jkYb&kYf)^nyozHo>>FZa z9lA>khrdTB^I3bJo})HWAV^@HtGMvjgxmh)10pB<(snURYXME zw^w44P-KF)?{9*jYRxe_3B}0Y8NaDYo^^+6G8$L1xK;0ihYpQVD%U(l_LlV7Elu~C zzq|S{R8To9Bja#tdO8h)*|^xbyGw9epsUiR9SBmjM{olNf?Vcg`KO~U>j$=vm-PrZ zMy7euEi>Bs_KgUl{cJ!Ub9Xic<31uxqzu11#yY*zk1?9AsiWiR%ZVVjxwi|c{5 zELDCa$x)?6et$zt!-k1`si`Sd+J+z*&zhPH4vL8d}fwePzHS&+cHYgBB@U@0R6X{rHrmq?+g2;pc-?Fn)^qOo5JE+xC<~8Mz&Kyz4 zHlYkgNY3SV`Em6Pu=eLJ39+os)=Q%ys0`c$GRmW{8L%ubB_)MyaqCvjRzvi0d2hE@ z`A&XN2MntF{yk@A9xz!F&=p0J@%DTVK*96z5S9ru4=1du?%utNR?7k?LHxQxfc6Fk z1}%wd>=PY@T8ljal~DMTv1>EP--kLWiV9bi^`2gl(( zoR5lfEr}T!F9zfjJqV3rM2f`#hF^VXQKz(I>J^2Sdq*&A7xzr7aduKtk`C?V%a>a= zJ=ns=nkWl%^Z4;&bBg22-fTQUdEtrwRl=|I+dX2mPbUyAi1^XwbQ+yvW9shi9@4qG zREynCS|?5U>rQkQqd-y^u#WQ>ZAz_aG%LBC2$eD`mv7guAVKV}OhYmHM5k$)=R{Mj zP=G*3n(yM|*w5r(&+%W01GV_zww3wOWGL`X?eEWt>Be*Brl+Ud{L&dn8lqBze^*9L z8D71bv}MbdtgeLX*RKPGPpiAD)%2KK1Z6+kv8Nuk9XN0Rt$RsH2b?;Kju!lejNG>O z#MxjjA(JatuGo>_Z0TevtpEtvM0>tifi(f^JI=H6S>>H>U%9SDv2(bGAeCk>a0nQG zD)3%Yg{QkY*am032kAaQ1FR=FI)P-iB%RxuYgJ}a{b*bEjGrThHR{cq9GFJ(06T3? zI;X%U=R<)s+t~G~YPm=8Tyl*R~REbslP z8+E(rBR|z(l>a+cK?5KE`Hc z1Gw|c-@Y6o%?FXbLkE_if~YKXdbC-8URwqI~*SKa{cm6SDu`>nrludqIWG&(sPL++wSPxg6^w zj)ur^BZ#WEn=*3p#EF7i?eE>3=bE&n#YIGtT{l70aJc2MCk)6_yASQ*tQ(k-`6L6Y z)z?Tza-NZV7a^s7OdN+ZpUwpB`nxoEm8(q4T@#)hi{$kM0jJ3r|VmcK6`%>3t`oEZ$d%GS!LM-XuqC8JlOMIc^ zHvAm7kWUbomew5_8sa~7D=OZ9!3=cIWn?)h06s_M_SjDvO;mAb|jm@M=_fZ4D(c(ID|B~h5*lfS@%O6>fT9;qy zEOs#kRZsu4Rr)YUD78nNn;Tr0haw$U7A8s;Ivi;pyV2)-rirJ>r!BB7;wj|%3{7teL9UaBMd;zmfG_~xh~t#_bh=FBqSByIiWN zwRIk_T5>J;6Jes2J<{+;W7dZ>yX*&L2#QgnlO#n_LL#etKBSR~RxH>3A<46VcU_B6 z=S&p1G@d?Q8p}fMqjdV$uNO8x_$Yy05yY!=b8{EwQ5H^`2>k=x<9rEZd5M7C{Qb6# z7|MpXV2>o94{2)4wP;+93FPAm1WjlPqXbw+T`s$(6b&CRvZQ?49&Y865ED!9@Hu_@ zUJR;J##%C8F%~AW;WLbvxx~;L@q)?)*J`)#$KsRfvj)<&5!Y0x*aZtL+uxe zl~){)>TH<8pf=hZ<8@S2#{K*ECFEB3?%n$o1PTs^3;&@0d{5&0_b0&a5ii)y&7C+t zev6lv*Z4zvLgqyCyi;CJPVDVt9TS^xWt2O&Ez+OVu4oCSOA$YJ1%kHEiM007c)-rp zmZI^h<=wSfvW-WNj2$^at2F2P_lr=(&lUIJ${uaspVf$6FR#+K?Ie3jDSR#O8LlOern-^2*FK4-#{KSjbs-|nsA-$16(vj9{7V7|Cv z+Tr8Je?A;VufWq-O2FAI{^R}+SbOEu@O>MsAnsu4s*=059W+r$S+}^OSwLn zTW#Cqx)Pp0=PY#Tu|~x<@K@A4fbh2mv>t2EPwyOnPx7O|M4}2EZ0>LZfe5auslvqC z$`qxe&`}ml$_4_~22_KTHpIye70ZB~U%{D|1xD>KV`>j_m|xK|=af@N%hy-vV8sCa zz%>R(RE2s9jwWC!ifF^|cKo*Fssb`<2QQ~~4X>|Ft%L3eJ|6?IB3uq*5K#|pL7!~< zLm*DUEv?Sp_Q#u_T_4;E?VAswWlTyNuH0db4gkb|fe+n5nK6=V{{H%tJTOY3R_YM^ z7ot5UyE1|4qq^R0_`9pG5!9o%5ZpDjwSS7#RK?2c$jJ27)m5@RWI@b{8&7e|^)^{R z?xl48{z5KQ4b2M|$WypQ#iM5L&kFg^>yKdXfr+CANZ^cThf$bVZmrt5b@vFEdtg6r zK4*RXdP>D2Y3gB-0@$m9sM&g}-GEDJI?y5+<~WGgG@k7}c$#Rr2crl}<*on^MqEY3 znoDI#n26d15P6%cP_zUarLDle`A69VsJ>*FSv!zAA;CfA*VL$J;9p)@YS$TD5q8&bQjTv`J0f3hMVw8Q01n&-VN2Z~7>755wEkmyH~~CNa&AQs^5ajZ5ZyRT zswA=8;Mwk@Sst-~GqkTSMG}j7B~4`hM9Adh+rEL1!oWby$;okZ=7IVPPRAdBNU-PV z1Tx+bD<^sUxIUU8FaA=S|0;q%tfErUHc?++k6P%Al7a%Gu))QZp~aPh8rDQp6@u

3njiZop4Dr1~}FPd2e43)&m4r47(@kVEMjjY32%7{{)(G?75i=ZyrU|lU>!4C}%+I^2Y4m`aHNP-760W%#bd8i!jn(o)TZwH&Z2N6}C8)`r{Dy&o}@ISVND zl*i3*QfB`@{9@KWuJM14|Cxb*o`E@*61$%VQq$5TV5b7b(k%oySKq<~2%K$o?#Nmn zR{$9*qzsUI5_I27XX_-@xi$W-m`Qox4$ZOd=_Ih1POJ;4;PAtU1g+ByJ=7XIQz0<@@^z3f1u^#WA zYV9@TN?WiHE~B78rVuiyV0gy6rO?q-JNg7#z9Ji`&9Fmcy#F;46VugYsmz>jE*%I} zeEsreB4{AT<}_`L=XewpHc^dqowz3G!KQ)>Q>JuO?_?W<2b*}xl*9wm zpc`-owrW5(I=rc=X}367Uk)Ea>kAfY zBdo95!rYv}E`8*B{rYtZRDQH0kD4$(i<1)zQAo^V=#ig6B~>YO4*(w|AUEqs?Ddh- zl%UN#^U#1E11rnj)gZx>O?a9M-Rv{gnhjAe@#XX93{#>tDh#D6SMLDMkUvA}D};(b zzMvg&a55;+c+Dx3fjM48YJG)Fs^Eh6CC5gKcS uUfMPN-Tqse1Bzd@=U-#?-}X$@IyD@C)rR<^e-bSc+vTbUc1Ss5E>|7N3WVQFAy zdYbzzH$T^J`c_uvmV!JyCja^YZZiu#o{8XKHC$wq`4u%w3Web|`IjzQEXsgFk&vfe zzMy0mIMVLwR5`P{I-Go}rht&v=BnYvhZR+=$qC^jfvNeXO%)}5--NZ2 zENATss)lC-=ca^{4(%>JNl!!O#D||nG`XnDDXdM{RbN4c3Y0GBU*{z#5AHinHRlQgkKVi8t zzLi2*@i}MtJzCsjchv>YuV1e_Pn7Jb8r;LJE~l*>dhy~#rF28(nUPl2y?gg^C*7ML zzs<_R5^d2}zIp4`20V;!NXXb|;&~DW=Iafc5)<}lImrvzj@CarAXJ}jq&hRyAl>P* zn80Gt`|&yLM{4!-MA;#u_8ew|@YSOTcxm)?_#@k!J zkLC<>Q)}lsU6YPod!;}1y)tK_lzFCPkJdm&t7%{IN=ps3ifZD? ztK=_d$z}_03O8rUkq?vLrN1;*xLSZ$h|tKj`E-*0fQW+WXUZs{5Pb;^K6Jx?{_;t!576?>6=g56A7%w0l>azm`%YG}4}{nw*@RW8Qr~ zRwW^pRoajJ*fEKin3&0_DaCZd2KDa@Tec`VIOMQ!h={baE-}jR1a6o+?oT(4%h}os zTMsE!zC0~?GsC#%@57hU>?XAP(>83~r$1C5Gt^mFh^zGV^o03xsv33{IN!*3NPqwS zeSM0q^tG3~;yR^IYAmZo`WtWSQz+#grB9hT`T3Qbo11B4uB&msuia>foet*SqWVUC zWt~$@#ltrqiu25cp4BCJ6({*96xZO8kdS?6jH8)Nvo6#{UaOmF(n?a*a#rr{?k=yW zsEbjIQvY84@uQrbT^0+6uyEc-wRaCZxAgzM=u@%%d`$1{fr>m zzd8;_W^!hxVW=UlAx@Qts&M1Rt8IrwGvHkq@Zew3R~xD1$RwZFdb_73~=&vhjqJ`7~{2QOB*TDGJayy7!Z zcs`4TkHvBG3P*ThH>DhBf7EmrKhzj{`s`U_hDoc{kFTfn94q`zC})~#Bxn_CM#+ZQ zWR#Vb9_Qmz;#5tvQj^cM8Vp51pU^63i*OGXaU5D&n7WaA_i1WnS()UfO`8N=ma?XP zQy=_x;A)P|NbFI`XYBm^4b7UVcduCwe7UeVH>QerOAQjOVWV9R8QAGen=4#RXiT^n zcQey;a&E4v_mg+JX}h4v;*Zpptb1V_=$T%#g*Yj6x~}H0S+i!kN@y(lUQelEUF1`l z5YZF4?TIbvM#JP#cD?(o@3iG7A5>eQY$P?TdU?19Ay!sS<_DvjO-2_@g1u-cn?yUa{)5>(tcL zOs}`BVNIxbd1Yk-ZXDaB=~!u>)V{Rjw7fJ`?XWaaMqX7pMnRlGbpCa)>x#WzVS7VV zd_32KKmU9|<2}iEjAAp=qWt{%b15k)1sR!V-+Frb#>SHRD*S~c`!_RcdJJTCx+v=F zN3#r$WOg=^B>M6thpX!&kI64QM2 z=#lFF6%>u~IE%fM)2C0*bp62~`0&lmH2pW^ikTe_apdX=H#4QYa3TjL^ZwY#5UZK* zkkV{?Bg6Qm`&Q;iln3(SYd3DI$CiuK9KiK5V^50FIj*_%kwWnib8=C28zx|&tNK5L z3EV2K2AsKuBcy!m*6WLxE;Z!ZnngrJWPkP!4o;+7yMbL;SY0_*Nq)F7Asq?J-##TJ zr9MeZZ2kK6F*ni;_wnBOt19qZPgNqNgp@n;msk{zQ>Wxfl8aT2yOY`4kZ|*CkceaB zx#~X{M5EKv_?&5jQ7yT)NvKI-j-%OQXW zWw1Lf1W=%>IZ$auDCXefz<|E%Qr$OmyogT@1Q zy+^m7C5`)JG8A(z6dAE;~X8{aGjK$2m+%#R6t;tmkThd}!25G}dNQ=%9 zXFKdJS@u^cBg^xiKCPk2BPOP$rlz);fx*^DY$e`7M{Le&lUMj9o?~`7e{S~B0Rqi> za+_(Ns8g07ms+Tg&n|Is@$9Q&wxfY8pA4;+nbMn$Ed=&^g(F~*1EhdQtYl=V)aS+B za*MMg6mirfoHg$be}SX~)=`Zaa@+In}>QaX)X3mJd5(yOO02XqA5J-Tm6*TiE%Z{QpPb zK&?3b!3t(S`h&UO4Sw<16wFO`?ENpl{eLA1MIR!s1w^6_9zS_f?#-JwL+!blwY9a6 zgPKm#&kWRD+U+4O?ayuf(&m4OT-^^+vi1SHo=pDVC5ViVd8vBUekIx*wVJ5=DAIj> zeFlIk4y(&^zCJ$Tk9M-7um^15eL(01??e?>7eCtPD7-dj0x~)D!=}nluDVMS(uWbsy;1 zZ&VzEeW$el6twvf4VZkcRr1;Xm~96Hqg9hMOGJ5o0z#^VsEn*EPwss>b$*vM8z@)2 zcI@0aQ+c*iA19zHLso2AiGza!CEI@^=UTZIlAQE$tVvO5j8_Z87lc|B6%?$xis+Q% zRIZ7NicU^s3z&Y%G}E#kZBz5wb?{)~lPC24O`J~ZZL*~lVNY_D7|<17Im3$k8#+z9)r?^G{s9i4RBF-_gOcLhT-4I7Rl$#Wb#R%+r* zXWloziHUNR3z>b(ZmuuD9HB);=lf4NzI*p>^Dn=UHA)V%LnW?y`xW^f@JhePjqcSc z9rxP0I)0ZWJJw^z$~!wd6PD@Bb;*0}3_#9KNlk6Yw$vjVwJ?U9o%gNj?LTUu@tFWT zOhciotH^xUAFqV%E%vHx>q@$XRC4w6$tMc-GRXhwP79N@?3>(}PpD>@+ zime$Yj7&_?U%trAjJDr2Ffb^oGGcOfm>xLnQ4$&eXQA zTX|OzymJ4xhn5}hX93>!x_29AHXEnhNMOy_Q($`dP>6?FbDx;9fBoq2Fz3VKH}~(a z(F-Wie(vch`)Gu1k(O`7SKc)~{8t+3``g^9Qr?o>)o3!v#)ovJyTMqdgr{^QZ6R?uVLJ#~;sq3J~4k&!aUeJ{)Yz<^O&zFD*0bDf8K!q@9}O z+IBbFR=o)b@U!9vtU9H!YPGaob4#Y4(?c1SGo_3PiLeTxC+;!8HNKM97GW4%BV zrH}g02fH}2!qJ|0w|&a5FU3{rEH$D~1Yn2*zzSrus@g1d;@MxWz9gX_l^QJ5W~#>7 zsK{D^z#Ie~@w$S%&SVxYUo&b-Bsc>V<2$d&(W95V9xs2o?zObM42-T7-i{JoP*A{a zawg!~nSg|kc@LQ9d^5CGa#ZU~({Jde?-uEd3ZL~djFO!mtj?%o8yogMI}theiCMjc z!R*GI@Sv2~O=%-X-koD@n^)ZaXNYo0$R>XFM{`(xy;8pz^%cL7-}lM@w!v?*TOH>{ zmG9n-oU#XCP>_@R8(KhH;~tz{TTcJ&0{@W=w_B)uBZVR-56WBwsfQi)BuK~>up~Wj z6{xb9(`9QwWhB<^)7?~#GiOwm7w4J?DE{Ql=6}17)Ob~HNlMc9Jl}7@ikYVENA!H5 z04iDaSs?F0g(B(vzofwbYbBJUj*{iF>~KKTY2LQ~oJH?njY(Qse!5uMt{uAjD1^L+ zhlh6t>8&g+3;}4X`C;|lqO zZtW9|SiTP;XJelS_StBYDk_J33%SedbrAt>yS(2~U zXPDdsP>o9?O5^!WQX-Ut!gg}CB|WP{O-V_}eglVA=Ov#npe80}f8PgQ7?CE8j~0!w z&rq&Ii|AkNuMCJnm}RHoNs3Z&1x>@QqTh8FCh@VX&3LyhB;~bcnl(Y^fvO^RC#OWa z2GpWW9&)?epsxYtb9uSKSVw+3LwHqje{qD+RJ9NEe3Vq8euQ^h{pGY z(cCe^==3}?)l)xZTr7m zJKG+9_>#MRZ8&xF=FPRB^l?8miM{76!bMk?ES;egK(TB@hHr?HJp@ssCP;(MtuXv* z-PaV|iuyziAyzgv%S;B!!KN@t&(8eOfz#E(VUTAG0RyWtAbbd{hJZuZb~>v9-N-d1 zYJj0NCxCvmr09B>=1r8Qa2}*c$-nH_)C)xiymMzagIklOzgW0cXu-&o@xat;_i+8OF^iUvu3kZkeAxf3AOdT5tNB2Tv># z(~WG4h|#<$nVG>lNlS|d)Bujf!fKQY>5jlQ}dJymOruk;QkcI=cZSQ1{ zQu2a}yZ>fEU6+Qaan2UiTrHrMAL;+EG;Cq0XN}o*qh+5GtWhFc>?;E?A&eyQ3LXJtG)S$4uQi8#7bR`?AhR-=h;C4?FV zR=-63h*ycD&5jIP9M-3>%Vr%vO{p7b%bptR@V(--f#G2MyFWJi3*;+ANICR8Jv&{> zZ02KQPw6^?!^dz))Tv}@cgNjLIF7n;SCiIWPtp_tkzVdD1oH6L-Rs6d^h88)i~OoYdzj|f$Ta24Nau57qy4l=Ty9MY{y0|Qv3=F3oE8wmT7~yS=~Pb8h-sR zzimArsD#jGuWO+rPq_A$f`Y=MI&?)ilk!6Mp1wQKZrgdHf|sI53tQ}v+Ot-R+LW}2 zERd#Mve~4wK*OXZ?Kw;SY>UwlaFV9Wg0A@G%RUa36v`ZXU5J~jC$f#AtVjf6lAz__ z<7-c*ryDg9;S{i^@$Kzmt8X7R^{0Vh#R0GpNOAApJwV8o9P2o?^7Ry-9iHopF5)io zQc{o6lDQg%!$K&%m$x^+GtG)*B48akAklCS+sRE^w_4jj^Yrw@8dN!((Y+3wn%BLx zZNI>40954b7gZ1u`j=dR-Wo#1w_pX%1FbZi$ZY%et{i(*dGx5;wuhGh=xTg86sJG2 zg)9x;WM8gneu}j0KbqCEZT-fLBnug~W+YVT8gQ#;y@qN7T{0SS)KF_?5-%_BieZzR zMI6?e9I7dqy+mpM{MqUy+dnjywz=Ju@@$+Sl{jSrfW)-4v><6b7{T1JW45;(ODuP^-Z zc)#AXCo1_aBSkn$ITB2n4bs7O(Sgx&+Dle0s>WuOaCzY zzUf47kLARP+@-8f|7=eLZk(0gQ(ZLs&+dfc!cZObNvq+6Ou?u<9dkCIxeh2<>5g-z z`Kv37g4RPmIKxl~qlmr$gzLqf*hHmLX=P$7Z*H1qi(|W;Y11{IU!K;WRV*qM(0Z@s zbvsWUv&n6bYZNh)%i{JanZ0AvktsRv0gcZ3`{%v+^WQuiRu=kyMmlmG`Fbdn_QuSnm#9TFv z8sqO}EX>cdA3l7c%=1takaf_=@4x>()RG?eZ2!4XU~WA}K$?a(mo|=c7HWY*SJ}{% zTo#G4rx$X@q^0*q9bVvPzrwUVM~X_lH*0{Bi58gUU>zEhNsD8JokldPh_SjZ-~PU> zD#G?mGopg_is!=pPgtMFcrL_}odaW*zd zSO99<$CD3uW!WPfBy>ISxBs~ zGV=4$6;iE{hx?PSxZf7=++tiG{T!=07gfDxMFhI<-^gX)De5f&dkhgu-9z)(V#7%a zC3?JkiK{DjG$-!LJSWLHz-$^)GBPWQNx6^;tp{sM7P7{Fl%kP(oP&dE+hHH|y(%aU zCuxv$rh7`ClI};lRo%6!{?D)YrO6>)oK-e8O+?RW26#$SoChyd?vH#9p8WXnV_Lg? zXlN*;>E$TROi1pocCj>o7=F9)t{qXTu}W04ya|a%d%VFWqNB^FuYCRMuU|}>Q~GTC zn{%u=_xP?yn?DR!vu(TgkhF_7?L0Ps2<5ILwMH+*Sp|nsK1nmbJcS;pLOt}V>zZIx z1kyV}$NGX<{)``qU;uC3J9qS<#p4vbAcO)J^3mN(h{0v7KB5qJ6(?zV_lX<57L0SK zY6f3kUw9?zoI?=AKlzah>xX^(h6DL?9d(F=2(;BZ?AiVv7#Og)_eP>secbQ)_;IaS z;j+rV(X#}VxF0r)jMZkDt-9%cgEP_CRr5y*vYKca(Xh{nb}MED3liv6nivq?=eEPg zfwI)vxe|%q2w2|$L%)dCz~6vR^`Kh+cFz|tUa+G`Ap)h5F?sG4>|~P}0Dw|)aVdb- z^RG|fa(DpkUZW3xZGR==m_cj`17V)AP@;(Ygk`Wv%T?LJBBjG+(d2-T&DAi8rwX76 z(zzrCd|qE2T{l_InG{VxC@dR%FdSS95^T`Txy^*$BE+vibWs;l*zw$02ycph^7ZNW zTX^(8{(bn>S+ii|a(`^t%G8a89OqSc z!{7dw3CRs>`S0*xg}x`27BKEzjEoVm2oT5#GsW}UOjY)P*+6L!^-io`w~ig53m?GT ztp=P>2D)Dvt5B2q^{V#guh52Rgm?q)R=zlODJg&Um1Qu&<{_&~KeH7;a4b$QNy!hk z>=C|x4u-OB=*Vuh8Su0aZU_s4S2#eKLHGLyr2dC{gt?;W(l|fS^V3;Ti{l0FP9#+B zp@PNHsp}(nh_y%EqRkQ6uR+}?B$Wy}^f?Fs7fz|@QA(!8xdV$*fwf*Qc z0BRhR4P2_0?DF>QZvajmGwdjoHa7}xnck#Xhc8Tj)$!yweOi&Elf}-}L^QPo`|Z&Y zw}#b;urPwriQ>V?sY1^2!Fc%7=6=K5Zlb5J|IwVv4_nHP{^aXiXo{p9lMVh+@E)ge z$NshdoirHpmhSEA*XMU0yDA5u3}ZkDg%iwM}F{}lZtg^H-FBf!d}^$c~71LgpL{zx~ znn@XzyDdo}Z7rCQAh=ZAO^v|{paLmF=wP7^4i0*SqZa!2qX~E}N`w3CSyjkWRb>cF zFP7YPZv3KxZ&nqm+Vww@ZiPKXU}oL>YN?Td2)A0#;E;Hv#-HI{1s zF`B$OV-gFz{FLd`Ma0BD0rM{9{O@T7b$o#EM@G=SR07IkrJ}V4X6Z{5ZKx$e{RVAW z$sjvqT~P==H+R4%2B(GUa8ptfwk&7_Mm1s_1pL=fsRxc_|LwQ)z*x31Z_w`+bY00q zN3q9vYGOkE;>G*u42<%|?nT!NOl}BXM`$h98BOtOir9@WE6a<%etzGL=ORUybyDZz zQ<6%*JAPX16{!e+TiEe-)P9RuOK{%Pvp?qYOcp1CowNU?r!lvk`K+mx7F(WA$#_PV zmK1ceuwFJKQ`G05F36*$dwT8t_K>w4pe0 z&D5;zMc`Ef$Wjmhy?PhS<~qg`lDQV^_1{a`dk}P8ve;`<5&m~nQ@(poAy=H~3dhDs zo4Hpb9EO2LZj(R#3?(krtr>^Rn*ALsEI8Vtd}c+Dz=nAE@Zs{RDjOG&aBt8^qF+S73c?WVecq`OHp|!W*FUl}&kG);&&basr-~x6mo?6n<($eZY;);M{ ze3=;@a$Cx*}3(CXSQGI?_6) zHn^tAPSnr#QdMcqH-hK32P@q6FM?Mo5#ZrCL_=Vi25bqR<@c*w4+>weEiv19RN~1O z^m>vcp6=r~eq4$i^2?Y1beJ0*Y5qozpxlG4ZlpFGyZYjF*+IvvFJHcV{MTP!;Bd6P z7AR12uDVWEECEU15cV3vR!wsTj}ZaQ_qg)ptv(zj-MIG~iqO)k3>LYG&vD;7h`uL5 z;*-6fMmd2rii-25&i}H+QMf{jqs@&a0Yjp2MI#5dB)r+~B03r( zuQ9hnvq4CsP9_lIC=g{?Ap~%CZq2Q8b9g5Mh=qorO$AGn(xh`KD?IThF?>)}ZOP~4 zk|%bWpX)alsK=%9$KP-93I`<~gg9M;YLGYk7oBDBsx40X9huV)V9fO6v{4f3RgdhaU2@-`fXYFNL~kX;B%Zc1|zTj z=Q2N&%d2xdLnr8L!%W9xxovc6hS86+PxcqxS z%YS*z|DRj!PdQVZpcgAa5JoYjj_98%C9gFFT|)-&e|F;dq`}2S+9N~+ z!>JDD-ina@{6dg|$XE0fp8N})jPMsPn23rEGixJ=a{pj0wz~WYEHmRi(C|mvvK2vQ zEi>TLEh#B603$0AW&39_1atKYht`bNe!mecyZ^B9X60o7w}Ge77n^6a{xtGxw;ssu zmx@YttwCOpPLNfJYsik@yfCk>z7>^o^=7S+Z1>%$xCcFv-s`7 z!-sno_q)2fE-WtQrjgtgFU7?VVM;Tb&S6JIxE+^2E+(FQ^>LX6M|prh)!h7Tl=L`z zUGTbZ&{K$8`_rdSRcGLX0Q~k3`4cJr_`bSl6scM~G@p6bdHB^OU<#-MHvEYpAz#%+ z;8Q+(6*m?Utpo|U4*bFwq790xVaa30&0DriSs6sU@9flq+HCwhB%$)j|L|%hyb~^w zB3ppUisG+2(*FhmsJ8uoJ&%&Ox&PPQCA=5xFHqKXeXC`TU0YbjZ1(%00oP8SJ?a}a zM55vNn@7o!IN!1J^E%re7H20ix!)dQSb!>G0JWGl-{Ywa*A;Yv%ShbyP-dclA02aq zJ>RyDv}BrvkS-rFoMQPv_k&@J2kPocS)p{?r~IM_iNW(mntpe!3hoovU^v8JO(ioA zySde)2_*t5CoBTlJQOvP_(dZbMD6YEAvR7~?L9b$6J`XWK&~tkDDZ|fqhNZ4!c?o{ zDG~`b?wE5q({U&!D$Tt6B81T)IC2Hy078=f=@BCW5yVarjU#gF=)SPP34?xEj98KD z(u5>=Cvv9ISqRM?D)QndmlX5NR?-^asNM!Ej=Og$?s3!W(Um`~3MTs{T!) zx09|3bQimvtC@?K=a_+RX+XXgg>E08{%bf*VldeN|K^;Py=kUdrzkaJ@lKHYBD^Av0MoVa8Fj}M%)xIC6W7u?}IrxA3{ zQX;8vB?lFLY*0bOT}wT0C*9jM6=+yuO&TBt!vd|h*e53Wb;Je|pF`;7Od|H9FDC+% zr6RG@)g&r)n0_hA9Sql9n@W5;Q zJM7SrB6RmL>UjoCO-oCsiv8D`N$yW70_}>2UmIf*>ZJV%-Gqh8UB(Nnd?l%X7HeT? zDWVp8Gdv<9Mm9v0^l1p~!6-o-w#xyVV2$oUtn2CuX-qbt%c}T5j7l8QWF~;L!%Z_e z(IX<%2_qj-kYv#Ek+J;#`T3pT)cslxgRK0={+i z5F($$LZ3gsPAUD&Sf>_X{xM9)wz=#RCYgg}U<5G;cL0(f#0oVM4;)PS(%^%Un@R}%gtlRgV=xqC+ff6O zN~Urk*-#bGe>XjtU=x zr%IA$0^VoHo!RtDyjrT&WG@x<7g25iLd{($_wFgZ(iO5%_b_C&cPww}*=;8G=ic5r zKfWdxGl{w6Z9j0p%=%%NP8o8=>57QxuiMJrl>EmlX$o~hUKc;4wb(;S9 z@F6pLrKdyz8jjS})z;FZ04bgbfYD$d{GUYS4m82*mO>_?FFyGM{PXDXvhI$?zaycowGOyF~T=L*4WU^c9 z)~_cYkhpT?uTx+c;&?%9tTL0pd4zUH3CM~c#X;dSCNlr&tO0F)C zxr%5+wl0Bekp8WOg#{n9XoyK)bZI2h5V8PCmrTVxjI~O7KQaK$LM-|?T(6PhjZkLE z!GR7&`tz_a%lZ%50H)n2aLOhD5aPO`hDI0}0m3{%JQma2zDVK5J zEuZ}@rGPm&7>C30>ZBI|P{Ui&@0odo^6F3d&#b~^=7(GhOn**JdDQ#)^EcQa+*%g1 zP{>M~H*LBnbC&*6h|}bw#QfPCbqBt>#vr?q77TG0V;*7_H3r+VbuaH_SkP4S9cF|z zLT?frgM~pu+`}g%B#HEUkWZQr=3&S`u|#5nNq=OJw>>nAM;@_9Itmb%th(Q?|Ce_7 z!Pqa$o98&ej)^H4=0I$PHQdT%7l~Gc?#xw3=gWiN3eus@z`x8rf&qynv^mr7R_dCipO-M4f5T z*ydpFhJ?*xU$!uOKO0vu#|eXi3L4c`7!??JCNyfkaDP+NX}4kcgeDRRs4X)+o?>J*(E#!i$NZe zJBtO-Yl)Kn!1{UFw_pwF!#8Bz(-B#j@4;P?u=UwTrh0pO2k?xfqHR2G#e-5okPVrb zV;MyGsB*C#tQE(Up(=_acE9fvuL#Uo1z+GHnkF_@FWmg}GSWj6a@S0)G>-um-C^L( zL*bj@0UCp|Qved zeEjmobcKXP+GuG2~K9`H+QkjMHt%wA-WP1yJBdPHP^#-0;`ruv0*SM@E3( zOZ~N63@%GZ?860T&+D>p1Du5ajgKf$JOcjNfWIGR*}E9Jta*V^ff{T= z50Lh_dAe>Aq*rr+{iX06J_TH22Ae89>M5-4g#CBF%~T3^*wgh}b~E7!@ozgQJkYEy zatlOP0%iRvUQy^$R|H%N+Db7BCG&m$TEcQci^ z0|ixdq4%eY4&yOs8YaNwLQ)NAvm+oq=96KOBfYnk&ecU%Ag3=Pb8TTTKWL%UE5l4q zhAzq6v5?IVfGX2>vx+I?0buzk32qkDE#C#n3{Yy?d*kt`{j;3nq?x;R1N|3Z{U}&R zcc}p;_U$1S#1kj3kq3Afd-*W3tfHN4m7ANJcC{#BHa=cnp?LL{oqgGrSfLqM^@bw+ zH5E{dNq?0Xf=D_=5hUr9$hD;RgYCYPlRC|fK|BruX3(x79z8Hv_>#g&8xtEzM#Duk zLR;T1FUfYFnFbUmC>Rh-0jec&Qo)c&v}qLfRa#Ra0cNeHxs`RS{^w>nS$m{)7cNow zo^RR19Sz?!fWqI%7CnO&<@LZ9#B@Vi1K8*WP>pFM)*;d%MeLBKGp10$n>+-^9@oZ)QXEFa}xgwXrcjzhZ$FR75sGyEp+D< z)I@)!aQ^j8wB942Kg?6KmRLvf$m|k@zEF1hB))Vm!M2H zN*;3Vwa_Sf{A5|`6M2q%dtYqU#uP8DaCK3P49a3Cv!Et1K# z?JF!9Ar-!9TM661Un+n;!5d0`tbpTNsX6UJg_Lg@hk)VHW8j37FSE_U0}XCL>YhIi z=lv;EEpVY3vpWp*9wplIG}=$#2`S|%`s7EUrh?j&vkFN1q}8mjeV3jVQe@Qt97Hu> z2|ZCEF1-7}vA^LGaUTs(joy$N(v$>K|3uIVWN9Z@rc>?gw~5W~#a0#tr+iBl_6A*&>J zU%7T|=CZwM+3eKfSNF%-FP9ivWfw|+xwYOLha654GG30K7vPeGCp8$<_HXvB&xAZ-|%7 zPL=(KZL*7LB*oSs+l=K99Mu=DPR>l(EdnL1q zqVsk+6rZQkwi4)DHilEZg|9!IyT!J=NX$QgeNg%C8H=&%Fdu)c`|a^al+&$sU)CW9 z8=qko;^;d5b{RtzBV~^NqHJA(9RHv7lU7#54&R}x-s*9L3j!>KDlT(5@#3xf{|yk2 BYuf+- literal 14301 zcmeHucU06{mt~pLQw%6Z@S&h&6^Rl|fPey$Gb#d-k(@CnP>^UKO3sJ`0Rcq;0SS_G zkPMP@o_*i@zV2QqHHN=s%vR;-CT!q<+`Prk*TGT{*A-dI_4JorY4;1 zJnW}f58tx1G_&C6;4uD|7qFX}>v1q?bi3dpo6Ih$SWqZb*U7(CQNoe>6bg@o_{DSb zw*Esc4vy3{ODkhDn&&rq9A10LO?@YO_lrBL*RyUE*)IF=S*_x^wbjp}6qq+_ty_1I zdUujyzUp1ob#e3gTSPCedD47tWBb;O&CmW+_d0vNzQw6wA&j0p}SA8pm!b{W8(0~`88?|T_ z#d||W4clJ5+DlGsw_9nXX~SGT53Z8`Zx1ix{QA$mK`xp@jj3A#9sKwXw^#&NUe#&_F?p<}#^$RUlbsELR#muMNoff8<7#KuqVie@E?Wa!b{@6RWnmw!2`2Zt0t%y`e5E3vK&PT)V?<+RCc!w(THq@Ub9A*?85|N}e{y z&?b|tD;u^QtT08%j@4KiL=R&fk0ni?1-> zr|niH;{C8O)o}3XvA~KaJB~aPoSq*{G#qXJ!f!Vo_DM6b)n&zLX?Z5M?(Uim)HF25 z#NTik`VQx=I3MD-yrd8#&lg$uqpVD^^bMDfk59hBX9`7ryQ8yGMdF?EJsa1iT>G** zK)_D6sHliRN^W+&L$=;F+XR&lqQ*^WTOSFF4>YAGCV%)aHP;*DC)t7ok&5=vS|wST zX58eB{gaE7iWYsoU-hF|h-#{Vf>Gwz$5e*nT}7EwwQBc`_wCy!k{1-#-iH5#=jb{+ z=ZsHG+;`E_)06ac6bi!QXwi^$N$1${?Hi+lgAel>U(aeAscYDvAxP`qY+@5V^l*Yr ze(wzz+ngKvLpyftU_O3a=J587X&LJ5cG<16O_H$zLO+kqUkvKoz&fK zJWBTVnaRn?lLZG%Z}nA#%+GeZyFU2*`?pbeSXh)otfKvF$77c%L#Y6Mg4V&MV|C52IYZ*yLaynudc49=b9X8)3UR(Q%y5cNh%$jVnzTxrlPCG$=nUYX3>!g0wHX;YnUszsLUx`#~`v3b8r>eY#JBcCRuUiuhfB?iqO-*X!`hHX2< z?>)Pp;m|50q}4V$p@RaC?+CK~yp)+j5?{xyc(C7>xF*hvd1Q%~@G?sEJjQ_M9wtS(ei-aJ#Cj8$o~MNO?aO-&1PJ zooA2BM>fyz9{qT`vpP{rn9HbMhL4Z$4UcJ{FNanFmC)>2WbHszq`SF=#Z)m%;_)+Q z&e$esVh_5AcW#f`=5&a1%sBW zD3rsWj=pdz@85Y;+<{K=cIE>K*CTiE+5a!ppuZQ$%W(U*gOuO)l$rO`k&<^rcvt`b zR~Dl^R+$Y{N8{mz>ZOpVDY*3@uMAR^6QOZnH?*nGpvrfs+wgTFSIy%Va`!#s=rF?m~0bKV93Zh#?I;(khP0ZnORNN$8jn-Z4?%A^_{$KRBG%Y#j zx}E%D?Ou2!y-CBsp~G>DUAA6pGM%%6hN{EGiw`z$-b}r5?LA|5KS|BR^y=wKgGlMg zr$Rp?i)$mzeof5f4LEJy@Nn?_@mj$qg;|QSj7)IWNRApZUhXZo@x7s$W()UB>!Fxc zYu0- zPj(imw|<@(auElBQ;$FPqvPqY3+L)b*boUmvG}6I^q!v`j%TgySVFf`Wqen&~DQRzr;n zXRLo8H}fnRT2ef$C{F7@t1y z)->lQuynh>l8H$|j8bAkb+tU0OJcpDkLB8=bNAQtJI*HExN+mC!f(Nj;*U1cq@vE} zPKVtVS>x?BE#$j%&xjoF!(WHI79Nyl(y*846m|)D7CQ?Z6110p|NcF=(q?DpCPo4J zWe&^2LpHa5z7tV>e?#QNqIhLxxMZqf9eaRHtDQ&$-RWB%&I?U#26N-x&)nVXkUy>h z&ZF(;#F@ufw8craxq0*E`{^f7Hi}%lNUc9%D==;=kRQQzu(`K!`Rm-Wr*(Q0TYA>) zlu&r8pW+$ppKyAB&_k`DJaOJ^>5lf_&JU_Gd&4Z2jM!qwZhDO#TqpcxZ|Irfj~BMk zuvcR(KHlE)U1RUH3k?Qq<0Yh}sg}LM_HpXoD)Z;_EOV?$GH&A5(bZiaG}G~zj+v2B z6y%LLJqIc5oxXYBU9so;!|f(|`iIin6fG?+NBy%=)R~!?CC0|a7-;hi>yxgZV4X%* z6VB)H=Y`Y8ji+^P-t7Cbfex7;Dj`rz3Ym)h_ak@8g;zd-rC2uT`1LPNlv6D`45ikU z+0i0rP}MyPJFl9XC$FcXjU(j_wSV*VZmgm#)d0Cl}9Bnjh6aHX?M#R8N-r?Q}uZdt&1 zWmT1=e{HvUG#K`qliH#xepvk-S#LW^^9McmFwWi;E|X?un>MHP<@vhYJ#Wi8$D$PD zRY^He@x$fr&|U3Wm4pEKvQqwFp-S>;Z8FsN3p+d7c|-SI%f{V@in$xKf4&PCs&Q}KZ6ft+& zcpny}f#eeQDqK?`*V)M~yW6~C2QD4HQGdT$%B`3DHp6i#DW{!>5T}PPKbZ78J3c;M zo$X+gM~A!KyGfs7)RyD)Gm8foooY4tjf2 zPxbx0z|(AYpWpg-)T>voc1C886&$#rLY#}`TrBmiNv1doNWtFHfHO)Ky=83HLcu3R z+5KGqTC@}v-TUM9uHpu)rk$oevK{YZ-Bsy&7C*N;pSNFYhQ;&>7^65`P~L<;Zhm;0 z!pO)NSal^>gWYe@+2yz-DZ?u?l@!~~=RCf9DIb!PQ*=u93^jZZ6SSX{0g4_c2l`os zd{$Y2+JJV!Ucsqqxi{R#Z#3=u!)1KQQGVdH-tnZQyE1#GHMTZh%@AZk$_GzeJ5-ps zI%oEmYpP|xY$Ul*(xc8*W_1Y~>cp9ld2w*l9n{lCL@1+lU|f2evl_IU@ZcPaVqArf zl4kUS2WugZvLV3oBj(0SIILVf zPaN8h1F7HAFLKx6=`ur+TY_eKTdMR!$5F(LA(>CN06pW1Gs1@xlJoW zLB0?{OUh(e*wN<)c%;^B*yerIX}&*le9m#8CCg^ij!iX12B%Mox9pm0|AA%=$UB>UW!dZ!WxeK z%Fmo1h)p$WI7PAmq8j||8EXG0`ts+lu5zNHqR|t9{8llHQvS+uPDP#!F^chT!Z?NX z!Dk51N&U|En8;(4mlWqEdjbmetvOB(Tn5#b5I!M)iNz`XQ@sT{X&Jw|RrBsliU}5xI|>9$Rtzlj;aOEHr0wEHAM?@TFhV zv&37jSu54R2bb~*2#ANRlM3k#p0`jlVU?i{x8eF|Un~3$%P;F_`k+KV^pw7(@gI(f zO^_w}&SlvVw<(QNWHCQ2?MV;_h&=%M%`uiL!N0mb_}m(@^pht~diu9zQ9aHUg(S`k zk-kE=c(&tOoi|HfkCViHrPF8m^hdOruD>7VI*=P?#4o?z`ttBD?oK9k-;x(aPDg!~ zxPSHi41Mw*oWGr>t9nWdZonm*cXora3raG(0#+HS5}_0dA6`R zT24$eQHijM%GP8Z$$0e)Sx;&@y2PqT=|KRn$cxpq0=6=s6X9iNPMwl{`SN9c;}Lp# z>K!|-hLv`XeeWEjew&t(cwNG9rNhxhJgaHQw@G91-biKRUv5ZbP!p|*lll3NAVWv} zYqQPFtcCOR1^D{ah1FQbx$~I*)L0$lvYatL*&o{6tghia*FDhiA+k((#SuK^77kZ6 z`R3F4>7iJVwmn;na^-!P6|m??`o~Wg`Uewp6+wxQiqmLVzJyoh?dux>_9*U|X4;kj zap9xC7iwao7^(^wOJ#pmq|ci-F)Rrm-+kAH*Om+25*M40DM6mRw{AW8a6Ff1FhLv_S3(k^Id5Mk-b|ry=6b>UU|Ov}Xa)mNcbFlT#ct#d5ps-xcG@-X4!ugw}3rCbt{k_##mEgx@(;#&I_9VYvJ zdWM1GlZrn7m2Np02c!>ympPb_RSgx8J=gO#bFxzMe);Q@+K-w|(${a@AGWyYI5pIy zR4zEv%+bdHq|D!0NqObt1GN@L7r@BGBo0^-Hq7zUux^mnj1h92HQP!j^r^ZK9!`v2 zkdtD$(8BL>dt+e#GxjjOJjSC(Z{Y^OC^D@E;eu}eSF%BNsKk$>4&h*hWzo9_@LNex z2~K)IU_?OOJoqQ~&|2kAC#;Edt_*b-iUB;I3pit=sIKn6jaDFvRCE+&Vg(hr)6xCw zV^Nvc825|oKW)eT_`^9td0(C_@FoVkVdmY zNy};XB7?^sHdXm22Ygm{u>V_g09@$4$J)QD&iqEfJ7?qa9zvrEI#s@6Z6zhcN&Jee<8RZti(71Ys1Bvj7Ttgp6gAaeA~~ zc_4AXkM`pUIaSp+%X8%}131(Dg7zsOK+6BPxj*L^JR$?_CCD-Ek`@TTA>1nVW)h+0 zDF9sDYW{ee)R6O63B!`u;YsN;&mbnV!M7(nfJ-lk|Lo@Whqx@fXvAU!p-}M0HszNP zk|g%vC}od9W!NUMS-d^(51w}X^}j^L|7kfTr@!Xf;q4WG1PIu$sHo#y`jr>Gj!FBT zWaNE*QWQB<0gpZrPfQKBs3Dllk_-Sf6|pI+Mp5|cCd!2qT^2j(=0ORk2%Bh3(YNn; zt#_~L@>}jJq;J7xSj!r(mM#SXrUViU z*hHswim6-7zHapl`zv%|OTFyH$F8GW2mw-e_x5gBLATHMC`>jy#66paw&iG^J9o~k zG0!@;O{+`b;=l8uPUW__Nd1qR3=eIB^1d{beCeNIQh(5tNh6haUEtxapmG|;rff5r zkL>b2#t-E3OkHI}mlxVr25OYFYChRbRA*WlhDSyY4rh%hoxU4v1NgJAAe#9ndWEm8`IMfIVm?Y>wKUv4s@u65K;5U`m43nd;_;r`B z*ITyGbes;%yTWTUlV`m6pgc`Lz*n-vL9@2$3DCwz>sX$5$pf`!jw4(5pRTBXuMH|0 zb*<@$yTCgoO*;`Srzs!nk=A&|D{pR1^pqMPtjylf3ff13D%gW`yOw?kJ93A-72+7B z{7BJU_JUcx;U79dZ=P$tGkdRX9+YGolxO^!+T6ayaK3#*$UskdvSIP=>zsj}1-rM( zNHs1fODO-nxRNvhbu5lMJT83)l&OM|Q5^i0dqHh!o7|t!t=26u;Z+P*4l(m z;}Tb1pAtc7md634+D+(Q2@=vk)6CCO*Yp?Sq?T+Qqz4oDL}#J962fNvwu5~}W5C`& z<@MLJbCwH)j&&9ePB)nRA174vs#?JtpSy!`pNb^ zWWd0+Zd@Tm0Vo1PQn$=M`ZcGXFaL8W&@geY)B2TR<1DD9pRae=(Ze*Nod3`5fRFKO zP$c|#rv)P=J&q1JvF7*h1S8n@YvW;H)_*nJDX7%{w`LID3sFFLK1f`?ERV)wO}Hct zV7|5AlLSTa0A;q(Fi{@_+P*L3F`9IY8nzt|iKd2N4PZxK{_xGXZFit$>e$ko-(COu zC>k&UME8a8j{uQ8qd`oD@3sN#pP3@1gK8s#oMUcx7OZOm%eJ2xjzm?sSj zbLoW`1__IOulCWvZmPj3QT*t%c$mS(~D~^AQH$GwX?hOSx ztV2uxP^Pz_MbUEHmevN}fi$60O@HT zyCdha+sWdhqN{+7s&L+dMv8Kz)FC?o+Cu`iNtYJB+~2U9j!x^B1v<6_ zc&Y<~i;;Chu-AWgy-%0XW9_%x^dfnh-h){orth6AyR53JYEnFQP+wnPBxfgF#VDgV z!PUpbA<1e%POZlBX=35Lz2UQnkO~xtMiB7*ed@}GD2Z9a{A4hJaDGwIM~&&GiO_Z| z?CfRzmBklt-VCEfVBOGCYjXShj##~Z{c};9TxvDf0i&+57?!Uh#`f<2*w|jASHGZq zuw?D-b*r|Y-J!P<%s;A~H+JkqK*6bVB43QJT?;>Z_^@9IL;72%!;2{hr}oSnZtv$W z2=VYJfuYnu<0ha77OPX@YtWby?L6_eEefJY%CC20PiT!yy|M9*@A2cuJxaQh=hryGi!^{s zmTB4lu5D@9CUd&cum+|Yebua^ka6oL699$05 zM%fVK{I`ESSRQkCxrNaeDZhceIkz`Sul+2+%E>8*QYwdGA&d~*8xmgR&+DCFqNmS$ zy0fI_+tXd-{bc22rsL%iF-!zRu_S(yb(#H22h|;Hn!BWka$JpZ4|$S?lI%R`E!J;y zmZsIvc&!`w=)aN*5CFIN-JcnmMC_ChI2=v|nOx#K` zJ^^?bgqtW|;>#Al*~K#joiHGnBw7@H<-J~QBT6@JyrXrVy$+u!3i)lnJlD(6VBynA zBqsuCfQ(^ONejmlP47y>QCrH>7RRQR7G*QiYClz@6u|yLom7i?P#4m=6qkjw)HSo< zR5Go5~nO8#YvVHbw-j?F>@^nUO8+41WyydRJNLnP`auwGbx6gj| z?3w3L2p%R54ryc`*^H`CF)DG{T<4`pUbkL}GA+>7VUmbxGor3B13eYM0< z48krVe!JyQ5gPphw|(#uUZDW@lm)~tjO6Bi=aD}yw%(@_%>~1RjGp}y$m9LmZbfBf z+}OU;7~=`n|M~9W?F{t@)JaBu{zh~!zBb%AWCmC9hVeviIS;#EiNAnd<=togsn@@* z-$h4f%APZOV*(6!kAovlh4Iv>$`~C^r+G^+Z||Fc*WE@X<>fqB)2V{JUV(uoo}QjR z3h7*a%Rhbby|k2z^!CLiBu+t~a)U1Om}XD;s^mCk>_gm$U%GSxHlkVP5A!LQgs-vF zWhsVrWthTh6F@Ub7rka(3`OaptTJ+Q*T(21+l**dVS;J`V)!k{#su0FZvmby&E_R+ z5#nB?9u`avHPwA9D0l-C^NdD9D({9Q&*IWjl8cbSk?b0oYnw=k{#}34xFK1DQ};&& z_Ab%i-@l#KQAeTCc<-WfE;bbp>~JVB<`&k`t#xg0eTGFOnZO`p8t9!5)W*M^pBYI+ z>>2{n$pB=lZRgg=5>}opn~~b!bN9Vrf|GcKohL%Of?hG1TR0@_tPX-^5mh{{!21Ft zVJXNd;wB&9HmZQn)jhL73^C%BqBKbPsSX3ii5pAOv(0hhIk9Z9m4l>tM^Y7e(%QeX zUO>%i`0+0UK_s%qDP896} zv#6MH3v}{HBMftgFHed-efkvM_*Nkkx1S_Qwy=NvoVjbE+!y|%Z0o)4N_EwLXSzR7B`F#I=34TgcNj(Q<{2 z3r8gM(&90rf(m|Vfuz`vAD4kXKSGMnQsTm#2huo@Z)Bts>M&Y(v4g5xU1QE36o*T% z?4WUDium7VzATK1>UcFC*dxj|Uka(hBO(SsMbS)^cRYWT7Z)e@oPP`$h{nJDnC^JA^*{s~nj7fOEG(O7InRZojhEQh zcWXl|8=Y{PM#FpU$H2Hy5PwzFKE>9v*=CWIBQvq!#se77czM=8C@2vz`n_0gUEZ@b zy@%)@;7<5#M}w<$9z4g}8Z8kx-wJ)%H4M+j%C$y3;IP$W2bq>Wi&F~O1e+s)K6DMT;W7t z?TbFfGfhEGwYu)TE_NG|Al$nYAYqDRH8iM+(E)`s29vsh#5G0j(}f2-X!(@awIyrP zr$TsnjEc*&RUH#AkwSA_ySjUN_Pk}pXcQrih}EI954%Zy0B8|Yok5)RWs};_0;$Gy z0V{T#N_erN=+vPxxYUMlY3GMbU0B2osv@2*kNf5JAscE*(M9F!hg)l&_TAh%p|f{s zrVWMKA~y7_v* zka}v>Ou5iOKY>wM?gD?ld4-QJaEP$JiC3wOtMQN4ilz@P<-UvHeC93rjti z8`tf~d)R{_i$SmIlc+wI{ds?Wktm^Q^6|trmHzPO`=IP_c>4)D$I-j`^+_T7c+G;> z_=Fqpshk$PXKhmZ5v-@4QG~g7+m1k zzVX$)d#fiRBH}*A@OuvaaCuEZI}m z%q+C*tD`TH30yYiq_Zf5?Bj0AP?}iVAU}9!hZAvYDZf=g?oY3;DcJ|VAlWK-} zxH`KZ`^WaxutJGx`sTF0C!mu>+YL3U=f~^NmARmmtFV{pR%XSP&}1M@KJUQ51VpeH zK`7Ld0QPkC6V4Jdh_YA-A7%#41`MFzEX8mMs+4u`soo?FCKEKY2$Nf$j1=z2t+1!% zkQ+2WWRPk@3P1?+)h86?BI;#EJ?Md_Njg5B-9XxH6?HiDco~xMV6eKCKNe=!6q635n@_JB)LYX#)j}%US)dzuH;w zyb6Nim*vy$M`IH%n+q$vq=lkEdC6SYrcIjwpt0Vbp6_6q@1~~i(^{GLBYqk!agrH{RI;&(@nrRY=)>q@+!zzsG(d$B$`74e#JzlL>f!^R6cZOGk1Rq{xgo zga?W8zFZ@RR!y~)SotCUVYYSB@Nc^MA9)8^rJCtj{%kHh${yk$FjM&VCaq%C=GBv4Bjb`DLZ|l#(+SgohJ^6>)rb^@1mXN?Ryor;JQemQ;=k6&=vuX1a(n7 zdhlTdy%Qu;Au2P*i&^47&NK7y)J+c5lvs|mw)}3*Zo)(t_1m84$iP#i*S)5Oj{vbQ z7`iS78+u-f(VhgoDd;wTjZJ(5M0$hVe~oNEkXScp8I6FGJE$GS>nmO)aX=U)g&$x5G(G0Imct3Bf=^PBTBjKcY08Y&IGHi# z;z`s%Uxa8&jG}5B5qp7K&$eu}>m}R=c~7#Be1`NLkXoA2 zNwNr>Y6O9{r%#@ofSR$0lF&11$*fUFTQdT+F#_MK(8aV^4;Ta|N_+%H*mR*OrTmnK zu~)h|^8)~$lUQv2iyNP?`D7C(CoPW^v)H%=(G~7xexWn&vR8Qb0Wk{8U6|m5I4<(t z9K!ORJb6OjYm$vI7;>j%kY@|Wr;0BU0Wa~r0F3#Qwv#M;20}5QT|`mTEi+S+WMpIx zYr6^1x@$U)i7X*K*v5`kFtZetOaFDleD}xXZttM5Ff|EROUmK3>2D2#B#1hJFnhj_ zv!Gx0VE!!Ap}!9Fs$0;rFPPuo`1}KpDEW2+@9lT@YaUQ>R|*e9&UqJh-p>4^@T9ZE zUw0x)-5GhKePi%CkQf14ssl{zG}jg>xd%IsIqvv-Nb@NAWB+^lsS_)di(9q!T~oa8 R3%8acE+Ta?;rz9G{|#|86IlQN diff --git a/test/visual/mpl/graph/references/histogram_with_rest.png b/test/visual/mpl/graph/references/histogram_with_rest.png index 69633c1e4fdbbb4c90a2e76b69b880ba403bc58b..e1fe47fe2ba26ab24165310b5a5b4fb8a907ac3d 100644 GIT binary patch literal 10806 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 diff --git a/test/visual/mpl/graph/references/line_color.png b/test/visual/mpl/graph/references/line_color.png index 392c42fbd3ae56d5463352c5d2aa61c038fe07ed..a7813e0ea07ee1ac6110a2586cba30f11a93c1ca 100644 GIT binary patch literal 105685 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 Hu0mjf=K2uv literal 144577 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

mqdZoz~R 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�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

9^;fnYgP0_Z9PJjItR9TP8 zJ%mRC`Av%t{=)I{2NaR$V@oYwjN#Yx3 zwThgi#;@)Qrj71V7G}wsC`2lJqhZec{(;VzHBs#d%|GafalG4VII?x+#(yNIpSw$R%GD3+Z zsC*z#Jcow<$WvQ&`l+o%`ByIgRs+hAV_EZ`|88n=m^yd`+$T+t|GNuiO)?u}goFvE zK&1)svox2$P+tBWnBGVV{RgKuBCo0J@R53@ujN^g`#YAqf89Rl+hdDGj}-(^5%D;%}KzzkH^7mMXMaOt?Cc_xod= z{>OaF``uTBf7(te>{!%GWk5y#7ds{!l`q?Z;CCaDp@P})Q^c{g^$#&3l`gw>mZ;5A zx+XEmW&6#L+h||Ru@c4WlfD3jI{fRL(`BtQKfR|bjxxU(gNsZ2pL}Q}#9>Vra%kGd z<<>(&OpYwuym)Ruicl7LVk?V($qOefk<4hH2BO{^Yd}A<@~Dk8;KQC@b%}zgRy`L^ zZtL7^M#Nx;QH1o-HF)$z4ugc$+TT>C z2XY#A8ok`?71Vihe7C~&j>#%N2JHC;1!a;78f#vM&B@tI3rhRJ@)7~&; z6p&OxasZU=NB?7TOB4LUXnJn2Qw-YqGqP~a;+8mcl4=(hJV!i~7pGMm*vx{b$s1AlX~t|7_{LD4+jip9y#kn7f2A?(5gm%M`7qOWmhaEn2(_ zkSe|SDPGb#ibv=EM?ov^Gq}i*K`Nd6)iJRqJEXhNL{YU&NV;o-Rzw!zfDc@HuPsLn zOU!OBIs^UdtfG#_#k5pLo1Kv~Ar2`22TWOgbeI(GF65*ZSW<(`s;0X?R58*o1^i7e z_nmUVH`G64WE0qvI(o8(l)hoc8HXD@2K!T25ilHD3!+)@70ya%ivLKpD6&|NG;&`i z6#xW8Ur%tU!N;iY5iYCY zAa-t)k4Fvj(&3*Efqsf1JO&dRG2T^!H+l=YLpu2k$n=tp7w;c3$MrPyX)*Hv3HUzT zx4mfnA6uxUozWL==+cyg3p;@zUzZ|@JZ)7&gZWT*>Z_NxGw#6swcVo;o_y`0Vn}Ar zv)^oL1QT7O-58c4Tz;ScVG?b0kYYw;$?vLHG)zJfEh8iz&tDM zx{;0h%X-T>z11klY$pJM>nQO=FNQ8(7HRGNs+|*OcUb3$N%ewlsCyqu0NMGz6p0C> z_|0~`|2tdkw-~@Hed0mvQh-b}3yYlrS^Mp;-&p_coC(*4Y&|whosKRCOej>2mLM?G zbMNTw8flbQ64a?Mvt0jn|Fkb=dk6TMdc&mun%E_k9cbi3#j#3gX2n;|zrzh)8{g3I z5l5%`QC7+X#-g+;kfsknK<54hbq?1bm$a*s zHKjX6-P3?~tEKrZ+z?U>Em3}omzc_B{;c5SvIe2sZ=cUf*=;|KZeIPTx;3E7o4Ov; zkc3Ockn=-Mi@45_^<~zyZz+l}Qt@~{^lPPt9}5Qt{Rs9C05DN23TD)>z$XpLlQhfn zMoQrn$w71ZKu?E=yG_Zc#o(>om1}Jrm(3a6d{EPmTbnrL>3)LS^Kk=6de`?XOG@or z%-~!Dh#<{_@c3q#g~s>x%><99=cd^0pxHEjloonUZyMOf&q=WK_;@zt7)V`~je`tq zZ(2IV$${}Yy&6ZF6<{6&MDGq0tL^z%lYCa;>BsM-a-AzBp@ZrwV+o11@%)&Nqr#Y)W z`&R9Ci1e+jQ}GwG9L(qUnvlO?phb|H7235pb{;f_zVr&$))XFnfR5*%L%4Nbq);&E zl~cTGm7#u_QKZ?{mtu4Q%feA%Te{*6*%>HlrKSA@CS1TgkJTAmr$Lq)np{dgn=|RGbGeLVdi#7)d)TUk@jPBf-=t({} z4lX~CmW#iPE-)c7hC|P~8gZBsgLrJppg{r?w={olJ%k`&irzH&7TuFg;T)C5MGF1~ z+^j^%7-9_#pd$!e#^f?QmcM$LZ>a~qH+(O(-#jmrT)W0@XnKVN>d~w@;CcRXv$TSg z9aZ>)#x)i~AEUM;iXAZZ$<8AxtJn+>U&G>3+8K&)ddKSvMHUPJbdHYGx!_%yBj$!Rh( z8w|G2=hujTD`(Pqzv6`Dv>2L1+GT)85>K;JseTn)v98>di&Z`pJ2aK>gT%n;hpUQz z^Z$)>q>elsB%Nr~F;CW89;Wfq20)AjXe7^%Ry|eDU_DnTMP!jq227mkf=ydlu|)Ri z3fNuSntm|#ELg6Q$+v znryt$QAU7<^*1?z)I8S=DAo#}*{74X-yVD1W^36(#D+Ig$$w~eDSz_JUp46qiAk1>lti!l;zo7*hs#h%jTO%mWMme5 zuf@!Q@AG!s!pP06JjGS@00IlGVT=sI_}v^DH2HJ}g682HiPGE*)?;4@qiXQ9xOP9Q z>=oWaLtEHYy20#CJk_GuY$T0~);diL|LUt;;oP#x57AmSnVtMvOX9MMCm%s#SzJ^9 z(c9H!b)aqs<7kyZWyWiJP?_L)y880K4|mN+>>=Xk^VC+~{K!1DarDbD=e^&FD5H-f zAJa8rA9oq(F0B*a-+nlCkX7+Mtm;hZ?=$4a49!oH%acD$fml%Q9;FsL1}zNv?#n;b zFSO*a0-72ff79Dv!)?@h16{Gezn2R|N`w7{MML%R;Y=#$^f_m-$3lsXPVrEx1r{o@ zWDo-T_{!A^Z)eR-u9%>ine^Z+Ec|5WcTUzly01RL|6@K3M)@Fd#Hz6_w1!G88#@?1 zoMVWqQRFZlD4?XfO#2cRGjp3Csfj{Q)jRNSbh&T(-z4ogEsb|f1%7+^{AYEYCe;_x zpn}SzI!!v5LcW`)pw#aF=P}FXkuwdrZth7Fw3Uas(gdu@t*3jIB z9nk&v6a&Ma>mBeWe9Sq}$rJTV*n44fdRPfWGWe#?LZe({MvAe2~n7k%gLRo>I06H*9bUe@m2N5W6qPKlc4+Z>zeu2XE@3sLQKqM8^Elf8DC z>4?!q=K@F;b2?JNz3b!={RVW_EK)!Sab%Dv*667^oeRWHKsQj9lSuj=C~nwqiJTeQ zIpzxOKM_*UBz~EPqH_4Eu-nH+(3en`SqOc7JBMjUBk2iGxK890=oate=wt&|JJ6moc`k53q*&C`SuzOot(Vs)Onz$K}#Ch9b&5&ic~_S@l}9cCQ`C@ zE!}QI3htKqF|}puLqC@fada5?eSv|g+x<6icN~pQcO@bymDGcTi&#w`!x>ugIf3{h z)E^J6HClZSIw;BGU0IRBc{t{I;1aTyb}@zH)5?A5tGf2qk$0#sh%a-^J}WwXof`gZ za`wYE?G?E;_zFbu`;ETq^3docmM1WD6DLou-Gju z4ANe1xefVw%Qt+tKDd)FLIc!wz4w{Hz}|tNFHaGxNel?|@25X^P0RTNJRS`DQZNX8`a2eU@zD>N zJypKBk1KW?ViEnj%=K@s*Xp^OaovK#;lhUc5@z+_M_jcs%0-sX8s*qhbsGJs8`nXv9!oU$mUU?3Ktj@9I1dC*@)Ur z&ul(?6Ub)3U8%_F=aEv%XaU$K{R(Wj7ZPK{)4x1Ywy;JZ^s{`)LB6^5fhS8&=e{TD zde}?`6(r-AbcO|pJ)N`wr&8i?uoQmt%j1bKlge%yxg>Y}bcUi~z^ep?VA zcI}v#cj=}^SLxF6i0WF(E3n+MR?jew&?n|!*YseQ&DW-EFo+M-t6c}=fHTV#3DMJq z!iE@U+WrxBV*2BDJr~t78X(z*;<%^k-BXH3 z1Q(&;`K&oMt#B8lXYr7({2!bbCZy#KBxV=%K6hjdf=hA}xMQ47rak+q;}<-rUZQe0 zp=Iim)yy}Y#`Jz$$!Nhi(kfk!7eN>TS$bd5e=x;c*N?w&r8I%=slL+7>7m0{_UjRZ z=*P8kJhO1^$MKT=hOqE}16P6*C4KZCecBetml9cLMdOeflRbX*A-!j5yyF96oWsJ; zDNVcYG=K3>uyQ-xU%_N&yroWY_7VtG!_rXnCw_U9atD`8Y)Cz8*XTH*L`=fJW0X%R z-e^+^0et(W+eR)tw3`n8sRMUkbu|+1_up zYc5zZ^n(b@+?KN{M*U!-XT>X;zwfq2Pbm!-TxhCmqX+V>nWa#&kXX!vr==}Ja4)@n zzC5L8NiJWR*s5MLlz42kBsxN}tNFB482~eKH|osDVG!4uBxQ$QiL_^rdgs^bAlX$N zr>94%0WCLZ4JAQkKV!oVXUWzU{qfnsw9@=}fUgs43^xR`KKMr%oa5J#bD~xKQdUPQ zt1pnO?*Md}luMKA_($DpJKLW|RAmgENAAo+aIwkux^mLzEJAc=`bF!Clum#*l~tE6 z0xXutEUCSV^*-n6^ThkbTm)8X#~Hb4r0^ z2z00}-6{V%bnV+`TK&dMrVg(K`pR2ckmaLtlWgseD-c@-*A+32uh%!vCe~-oz1#aF zCr+aDps~M@ek}>BnOiVTT-WK|9{hR1U9vAGOoqNt2Py)0iyct1Fe$x6@5K&1dQskz?Xkl|Oeypwg|vzge77 z>xA+Sw;jX7+SGytQzDTi$U{{pn~8`RR>OiI*znYqj!gBoWMq*P?qG-rKwXz66C`^Y%^Vx@M%=7E)4A zUbHfF4zoU>lPMi=A{$yiLs3L6QMy}|T$u!CCjHam=ihVHVU+ze#DuMEY2PO{zBoO@ zWi>9w7uZdC5^VdkwKlH!u03I1zD~dbNy_$@GmpI@j5gkXU9K)70m=u%7n;hCPb4De z0BfK!n?+}|1^v3037ohRuy0dkLSNoO9uF7Ibgi8SC&2%of4o<<-K_$FK6h)=Kz;K< z@ZrEmo4Y=%5E`KG0sx%$xPj$X;aW!lK%zX0sEErER43nrKp2}(T7rhXi>k<{g2qB zuG5{JX=^KQD4lbi=_=iEN-J|_DBiWi2_^Mv8w+l@w3oiC@$)a`i)l=nIYV=pzRuFc zc7?Qg9iOf!45f6Xx74y&)Rt&OzjjL=^1Dql)HzfZ%&l|Ub=)Bl6Zh^{URk}Bg741} z+5&NY(TT;yMZ9HbC{RiMS||Q-WcxcrrUicZ(0*QBDe-4N?RPr}ktR0E73BYcg_*72 zp=@baUb3jNYEEhfa=WlBJ20%tw!P#wE#E>@+K$GjY-}&%K26`zQ?`Pv^CR$}|13mK zypcCJpLh6&?uotJ!J6~8Tmi4eNaU-`g_8Gp(&s5J5!FgZI!ZRN{mHh6;gSJSd^!D3 z6TH$yR9@lsj_eQml6vIwRkC}?;{>VPMtcdo8u}%fkqY#!UsG(ucGLv89&!eLsJO_x zHnT!rZ(9T`WVYw-T@qGqk6CqD)Ge4NU(L8)D{BS_ybzCY-m!iftPzQXl9p^mFm z5ojhFyz{iajW%xp7JCvb8NkR`JrzNm2MaSbU*+|= z>mwQhC-I%@RkW2KJD|?vzDo{Dc5@6vv&#Sz0+ylP@yYh8gmj+uYac8r z@T+H`o?nZz#-$-4B+f}7ne^m+VtaW<3y0BI?jBB~|MMF(Tw%lt{Ql20ADzw2vRXKr zJ5M7NV?LT>zUj3U>gT*I=6MArRARYSnrLR?f}Q#&lgbnlumT^;^wi2(D5Jk>l$_Q4 z=R%Dxy8cu8i#MZ#)5?HaR0X&Q=!S_8R!U9vFUeg29;@USld5$ypZiC1dT&#+7oGP%B-g

    4Y^KT$Gjx7hJ2N4K4y%i5L90&2~-G#~eSXYya={MqLUvj=uNv!5~IOUh;!?>@XG zxiNU|^ebl1GcUD?lvPT~yz~RrgWHrAj^>;0@U?Lt;Es)5E7SBDAd72%!7AnjeZv^O z4OArj1ybN+J_9TAw^4r>ZggH^#Gp+LW@^&)WZIWl>kS=k_&qBlml-2_R@VX&71Fx}4^G?(`u~~BA9@CKRA12XLDp(r8VczXAsfZ?>k)UYY zms(gHJhEJ@9dJpv2ur#qW4pO{WfF4zd35d58%=Aw7<}b5~QKz zxKhm>TBm&_W6OZYDRIyJJ8D9~S>mnaJiwsvul|!!{2UbK>NgnS!1dX#mh_b<-{M;{ zZMAbW$LbM?HmC(#R=0ov4e&X>2yhG)7E);#PuT75Js5Uo=o8eB5+cpfzxZk(uP>7+j!%6=o1aDujnmzXt7-NN zSW>o#?gu^d{{d+LbN8d#sEL)Y?NQEFO$AFP5EwYCMk#_UUz7wZB0$Y#6~@k^$1R4+DN4S?dBkwVSrmvDRf)@i6aXUA&l5C zTBqnhA~inKj(Pigiz4C}U`RASM<-%FVAo-fM$Q!A6$R3KiG(-7T zNNTJnSC*j(t|F0M&B|(IGy;|W-4!zOYUVKd;BVJ&WcM9czT3S6BPJ4;3re&)k@lw4 zcOOy(J_kvY2SCHZWw=4irPDJ~bTuXkG)wgrg3m!0KC`iqq-y@K?aP@!5m)2sQnmb| zgJN=~nnp&DIbRf8bJJ%qd0|S^yU7#Oz5t?Wdu{k4UsG2BKf%|lYJ4^((cDp!iVz+T zm`qO588>C-U+X>{XX|voK5u^46~}&Te*Ll}>6h)G(N*^gp>kk6Oyosx(dL=Azn1QJ z16q|g!xVwWESykDYC`zPoR{!%Yfo}bJM*|>%SH^*`FhI1)xazo!s<^pyKA21WX;O2 zv#f5Ii+;)_aO}>w)jr~vbMi1X?V+VlsZRc6((nn?nLd9g%YOjrrUoWKge z!SX&X6uloJE?vGyMM?R%+l1WRiF3((C7VG-6og@M8K$@QNeO-*F}tw@v-vh`2)#_P z=97(#4E)%VVak=GG2+$A-4)`*32;V*J5{_LgbRaNAeny7FyoqTIS=bzul4=@a6`KX z3sT+vhao50OmW&4A|;jS2PFf7jKz=m@-Na9nJaQ6lZDawhX!OiXc{k4?Z5~+f~4=s zGz-kI1$V?ln$sE90H00a&g|vok`h8zXhN`?eS7)#!lX_Qh%0rO-Y+}o?z|TXnc+;* zQUQbtP{B<~ZrQXeXK2o27H~dE`w`0lL(_SH<(%0^jmuTKPok1Tr0PG8Wjx}oC`=IE z!rcEgL^}(@+ZODg3@=Lf?fLWP@8GiM>YQ{!d+aS5Q_Ap7eZg}XqAf{{q~Kb43^+@y zindk;NPzhOF`y^^RFo>DOG{kx8q#jNqZ@X3&bvaT=nS#+nfs7m`B>~ zfSweq!_?x2Qe74f8A#&@wiOB7qKqEb>oVQ{211e_Q#$i4{+^-0yCO&wFVFnb+kUq9|oQ1pSKOUvI zJq2#7P9yQ?*DteehpoX8P=cVZ{;6bCKG%li(9Z1dGG!4 zxx%HH&+Q=O9GA=2oA3@Gs={|4nmU^M0n~)Y{7U+kSX|Bzw{gR5C*~p0)&#^s5M|hN z5d4OJ@I980qiXkBSZr^aHvN!FaAhK3)2M|+_5<GV$jf4{FH?7e>7`&@A}D{Et%ia3~$watRgt?#)##P=O&ALuY8xel1>fDZr3 zhRmI-9kvOjay+b&6_;;wJngQ$-L_sNHZeltFpW1p(3797UL!F6giQ2mISv5H1NzfA z+&){GG?L%Q?@vFrvD~6<6%o5GN!$eV!4|mvue3C1G%KMO88vHl+ouC z6wx3Kn!cIaxdlipPzihcu_gMPyk+=2MtN2&jV#^feB zUIFf6L`qdYuL;qRLqy9xjA7jG{YN-R4^n^I=BAjs=`mrdfgH|Po_80;SjuqD`PHEaG@JwQ{AskuiI_| z)m|~^v$-?lotb~0M}F?MyfuW_{HJ~Mm9sR9+;ts8L5(dZk*R*I`uu`_6=Gfq)NsB? zUNSI6b>Uwx3s~0MzZCu>jS7A4a}Y|q2!B%bAh9FFlt>9Z^X;!&a^;KP`*dI5&;~xX zjd}ijh|eh+qz()BM(6h|uK{Bc(9Gd%oq9~7fRtxw7431JT&WOfVrcmXqD1033t<_` z_JnPgfbN5?vQqhzXR-CJ!sI2gm9uJv=xYV!f8YCe-wmF>cWM4Yn&Z;~QVZ>#&6ixH ze8({klwZ0x53B6DXTD;#rW_(R9jvbZpT6EQEXrsL8x{#^7#iuJ8|m%_=`P8UPDQ#K z1wlFlq*X!(3F(#?MnR=pN_tQ_-i_y+>$|=m@4NqUF;DFMtaY!o?zL{Sb^?lwXkbiP)q>uSkthu?bJhGV4#=1-9<`4g zfw7hbSq3D#O`~9<{&U!ql-TcX`pJ`l)=vqP6|LgX!=`Ywes&+i*YSo5Ua!vV!U~h2 z-`4S_#~w1C8`R*k>i{V?n-$jV$*fY^5py8!aB-#!E$P~dN#hT;Q7bpnrnKVC#v{mC`H@R4TyYOjUf;^!e!MnxGn3SO`l zRJ)-T_9UmP;8>(p7f=!BJ@?>TNyr=IZ8I z+Cm&zwxa2$t+$?e{FVUv@Ia9v+hN4;b-)Uk$XB$I_4T+fcpbOeHvdU>ZWUy^YD5>? z^0Y8l`|!AXpzyiYCu0~-B$$k{-vNb|>|n5OYCmoo$^bJIaI`YChvF=FlF6)e*h9`` zw9ReV3~6=tixy$x2uW@)zF65#*=5mO0D9lsy-4RwFU2xOWEylEwbiF{b{EHJCY%S6 z@|dS4t9o5Kh%Xne)ms;Gt0;ebTCmzjl3zYyQ9=L57Dp?A37A?G!zVKe&VX?t+kxzL zKg$A`V87{@)(z*`?p20t_TR@EPu~I|dc9V*(L|E^Mr^x+=WZbToNuO z=f!;iFV;vz#lZ&px99u_o8KUA`oTo_EiJ{}A%EnkeG9=JqA2WIx}G>nF`|2b0a0$I z%bvCm6a=iRUV=R+$rD2MQH#6zVVG)nZ0c2QIMhxsM>u>+*4G?>#;~i2;j6r9D^65p zP-cml9a2*B%up4}%1}=I6{R=W*_=Q4erIot7ZEz6_D%bt4u}u{6o=3VfwshsUFygY zusI;?V@ab>qqzV7@SA<6MIra{k8@|A++~$4!IjylD|WPh`ddGh{C%-tCc0Qj3~jH# zEIExrz*7&n!fujYd%<77WbpWp*C@nuiF5Efq^PNZ2_?>q15KM_f|<5V|t z)Z{0%e7wn>u_^_oMnTDZq&%5vT(m3)1hbN@8h~Rv97u_-f6^|3bSou& z>pOqBCfyQ9PF_uQio^QLYIbS|>hzb3yb}HVS$%*(i#7n;>95fq)iN(xhFX1~J~*@3 z-XMnzCHsGT#rI@cAl~{l!PDZundMe*r9oDhKqnx>o%3 z;kwj~Nuq>dKKZ-hgF%Vy^^C6&2&_?|F&%+5DJ)=GrS1)add0@Qc)vu2p~@xio;tPV z(_F^eI6fY9k5BsYs!9AtU2>=%O4d0{D0#~pl|k{$y8aCXZ=q|-ZU;k=@SQj+#hvV8 zpy@R4n!2}+t~uqmaVkkEu55P;NF>2*_!QIpnih0~XLP#C($BHTBCWXzcndLVl@Hk& z=z)d5iOru9VM-sNA6o3pw7=doyHq(3yd9JT7qA9ApZHze4ZTYm5NkTucu9UU0%Ov*`JNEmaTj6@4cVL!I>fFu=)JyRf~O}C(#@&5RQ%Moyun%4z>3G z5CQhI2WLn8S73K7eNC}3U4R|a<%I`!Q}4m+h5jY)uH(hFRug5GPRri=K&e#jv=?-w zYul2%;z@aH%dO)BW*2y!neb+*pwg`4qh=Mx1(xEiyYnBRngpbzy_vsrd37xBc=_k& zDpOA~3}+wQT=m}?s02ftml-Q(PYdhf%4wFqY6y|ad69pw*_jusBo+6Ditn=}Bw$Pc zRh(%0g5JLa7nK2;Lm7+)$xdmPPOCP^M+rJKIB@#Wb93mx(HR}#)Y4~(eDzvol`f^L z;)gPD^_tF~R3kap&Kys>3_XMArp3~z-2=p@2>iyyz!s_Vpu zr#N{|;rroP9L)&$2;hG<8Omt84P4Xm_Rd6xs@Eqszi_8gCdHH)?K=Q5%xeos+NC}H z5fJlC*BJ8!BgcWL#YKx8cAAFH?KSr$Ll;hVS8KKvRpY#7{qdLj%okUPhm1H#Je#p> zs0e$5<&)nrvdvtb3bdNX*~zN~T+_n`ocaxZ_H(yXUYaB%U>{v}Zzz5=KX?};F?G@! z_+C-t$R=L*oH#j4HAy|;B7&$nT1uVWO;qZ+0GQSWXxP|kiR|Eg^V>tfG_3F&@0Uie>RrFOWJdv9X(1z%KRADk z*+YdW+ zZExY~_Z;aEDCx!Nq>GMbxBX^O^@zaJ8SfKUz(pnLkX(rM*4&os)YGpgyOM$OP7(D^-1q z;PSfmB*;VB>SmjxqG|gxFf^Wawcg>Ggy%?D4xJa@_L%mYUlk+KNBpZ{5*V+DD z1bD)p4B*5JZ5$@>^po({jSWww_~8A%+!h}q2}}$8#O)Ti0?vfQpMAS9$+flF#t1vd zd>w$aYJrlx#Z}3(oNo64_9J+$BJ?`3JVfJWPEA=c8`#LQht^g*=Z!i+SPgG!`tB$z z-(3RJiy-s>M~e5G4;uh=Q}Cp?3yo$v$cV{~h|?D^Xy0Huaki8A=&#YT!1|-&B2TXL z!GaCxEkp@ z!4)P@q0inJG05^d%Mxw)ATId902m|>cfbjlPZ@FlFqdr8c1G?#zY*;7(3Dn3=!4)c zTu$mwVoX#itrL{ATIZ>a*L*yl3Lz$MmH>@#HF?993JZh2B5O=cyh3W0End%}Yn)83 ztOxqRsJ=1_c7Zq;m~e|fH$X0Umr;TTpy5#eI-5QqVvkG41V-`G71P?_wLlQLeojX0n&Ci^b35G z89K5n%D(M&zh_m%6B>!J%|-#iiNF_ZPHqKm&FXcXBDo1XPgVG%xZn^T7|jFH1o#g1 zSGz7olNk#I=O4Y~O)4%6dvS)UuQ@w7?LP^R=O9C7zNKU}{E}H7(U`w66|RN%=8r>0ocU{qLJ zuM{8BwDdl=S+}v3lZS13rDLPnb(U9k{F$h~e$sfrH@B=>5`=fxSZ{q;(^J2sQ}7JH zA6k6B)m9p@Xma3>E3$i5c*6U9?3Z`fL#||2XiFK`;kTxkAnS_Y$}BZDIWU|ZW?TA#}g%<3zqI(rouksp#`rK(BXC z&;BSmH#G1Ep}#;B#Hjc#5sESXON*?gi{?cA=iYI`EPoo|S~SzidQTn5&?2xT`t39F z7g&)Vr3F-eIs2Y%vG}XQta+5pU0_%aw(3h&i>157ki%DG22@|>Pyhv_+ZaNergc9UOdgsu_Ye%uLshk8(N}+63{BU}8Q(Bd!$Da;SU z+9NCZLdCs9kAR*O{gHFLXjzi_f^Q_=pAw=)R1FCIoV!8jhx<2%@}$FpsHi6P4?eP% zhSp71G`zm&gsNv(;3~{-BuZU?c9p8`ND@qUtQ60D=LSu5B#s8Uen32Fw;5=J3=hJX zVBucxgz%5fcE8wYY9=LY{HeFRV`a$j`abRp*Boxsw!n{0O}Sc3QX+Ac`@*k)n&S@O zKNX=k`#JYeGt9Ilq=g_mS9gOCa^?P6@IJ_fXzq9aDAt)J^@_;b@d^Dw%Vx{9cEtSij$mo6^ASgWNnf;_3lNWI8fSyYa&Pl*RhVZF3 zW=Lo6rP%&11tYrmeZ4x8xlkFh$M^e&*-s-OIbSCi7LP9jz4CbkJkq_7uB(d+(p_I#aw59gF(|M%J`a`to1 zZf|OVU?*E;nM#W+-!glIG~6OP%$Y!wBD)d@&7c=^T6T2kJ?*WM>k8fdHu z$*zW9rWT!YPELNRlyRWek~`me0k%sZLoY2ti@i`SP4WPKt|ltPsa8u%~> zi)a2$ayY8?M=L_$(Ub`ffs%cR3FcHkA5iDwP_wr2<3B-xc++rI>Tp~RcHJ`HMQS=3 zVN+A$OD$f6oqycD;fBbAz5Y0DJ6U)&rT;|4dQ*|sr=c=5W!_L(uy6?ja6u<>#~>-c ze&>xg4z5xS0+!1X$Zw^SDgu>VPKk;rS%-~V0@9%x z{>kn)pIY{XNw6!qulsrwB+Z9%Xb%AqqI;I8jFh8+>~}ztUf-f*N7gb=Os|w+Ey=sTvss+*HL2Yu(CDhbh*V z1{aj3twP7v97uDzSlG_O1vy^=9Y6L(qJ>L;8rt1s+T`Civ+(WuiHwSDQXaZ3kdHx2 zGC)P)SuFwWWYFTkF6H<11;K4anQGu`{({9fb|{Kcvr1i0+(+<*3rGTQm9^3uCK-&{ z5zcRU`aFT!XDYETx1^5Fa7Km*e4G|CTYM%UXL_Ab8IS}{QUqK>;ZI*M%x7Aj1=G*| zPQF^-q2ZrN+4)N1SZB4?5uB`b;mPC;VxNrCQAaj#0$g-9e&<2SmQ6g@nCRco|Gj(r z>aWXUk}!T~n)nKd0g-1uBn=hN9Ydntz54o`;n_sxi5 zgb8wbgR)^$7G!F)7!OPD4fbX5RN&9)FqZ4_K`hbJkbS|75}`sM4CVP`;_bH(XLK4c z+fVkFQj?eMl{JAYfGzls#aTHZ|4yM8uydP)emRl&zkt}W6zFITNIm(}#YdvJUKdv< zX7NgU$g!z6JYIf!?-rP;Z}W|8Bsc}zG^7D1|oW1H@{G8JPRPS4fqPKO#IMvE%5GNzf{CsrA7)@w9pym z&j9W48B}5nh_DZep1t2svTssYz3&~);I@$&1;n>=KHeEIsh;xCE0uoEpqxVEcl=== z^*eKoXM^W)=i`^5y3@R0qF^tIPzk{j|PVp3;SU zl06tw?2V}M&JoAZq&VD}!55tBs{p(F<2_p}S!V+0fGK-IN>Oq2x zFa)ndAhspWP4R8lZXz6}R{09Yn`uaz0v2x{TVjP%rBC>VC&U6w1_T1tY96WEdhzTns z+2F-}Nen;JTon%)bQYPMA| z&G}|vv$~U_*?K^bMEzhZOw?VtlzP`i_nsu6${S)3;q{&-_M#Qlifk`U;eYwUxRKQ9 zIYq!>LAAGwW@?PuqnA4p0(5=gjaU6Ib-BX~pWEMh(AW2`xL7LB{Zm(B?Y!Tcr#h`?zkb93i+^2HqDym|r+QIFW_B#Z zb2EJ@=Jv9+Mm{$&V}=~D>-iUDyQ{~IJLms~bUEgN)Bc2yrME$MxeG_=!wS(rx#K8e zQqdhgXAS&^J%!K?H0jV`o-aztjilfSOBk(L4z$9AQXZHV7CaL0^f1}+m~D4 z(Nv&A_29=v?Z@5wUG>|ej~HYz4dwpU#%bozNs7c-N(NIW0KhO|w_0~wj+g!=`@xw? zuLDE48pmT>p?v)3z*e$6S@R2~xW)zo=g8TZ05F`SDW{JdJ?J}N^Ab!@0I?HPLPP7s zGkNS0b65XH2fdiL^veu-s{o@ngXV(;swMISZxQF>0PLj zV`R664vKdXXxsswZP@We2+}uW)uNU)1#r0MH&*@(RSUTA(MkooBRR+&R0LTHlr>eB z)`ct4={}M*KYSRkwjkVOWq#%^{^NIz2`W*2BwB}b?Pe`)7PXRmXR~>Gy;H_FblDrj23dCaAcq4)sNK*>A&^vX zJeeGbf&tiT{P<%xXSVr8?r51nEbnt|>o4zUEW8#894l_u&NDR`|?a4}k z51vb@R+FLl`11TaXtjZ$F}@JC@f)+fQk#SXw(02E*UygDD2Z8-W^AeS>0VoeuhDcY z6I~x{o_F|(8vJ%NOx>t4#5r$_cXe9sGe31^-I4q?ErV}+R%0!0=1KlPEEnc=j~5D! z1TZ$H3}i8cOXv66`84%GE*m89SH39Y)`BJxhRbM~oe~7Ym9ymINLFi+F`}mwckYnB z)lgP2x*mgd!FwC#)mSpbz3X2Uh73LfZ`dHqH^t9$kWz!czoxFRD{a|4a?*l)sU%Dw zoc#SPL2T)$=og0f2h!^kPNG5|!tq~}x(0^bG8b{cmVUA5y$@KWw=}#!^yvRaX!9$Z z%D5>Er;&g-FY>NVJZxgnjU%+Vz5K(J$JYva{MNB?7nMGH3G!x-pi`Iy@9CFS`vwq8 zrWqbAH+2j;-#J;drI@1t1p^HLon6=^Zs&=Mg{=B(KbAa#FzBcF0-H>79=1#gxVY;= zi)&{=lrz4&`HQRG7Vy6LJJ6n`Tsu8&rwnD>jASbS%J|vMG;2Sny2>rCev{b|4fu<8 zx}xT6eh&z4mxgy;{;0pG-*^x^y;O1hwLNxY5`4G|#j3|7@R)&iG2ovW( z3c=+BR6~$hO=Pj4EmXhGRJ|{htKs1a*iw#`*yCNcjOf!tI-t}Vq%w@slf!O`mXVhV zcNcXwBaa)vT)&2SN6;&;dbxdG#D^S z+{QbXufo$+^F{#Gxu13&Fdiw?*wat0zNCWieTu74bTz5hz_UA_J+WC&*06a z{6sqbG`3y9FK4sK&Z#Raj+5@^Vmh^dd-v(gk5!U{uu#~NWB=*Ao`9t&dR(8vJr5N! z$WRk7^mjd2xm#i_=Q`l8r!CIRU-wsFT0^s?PJpnyxSx8U(Hj!bV*nb5Yb{?%MSha9 z?Y=Kw^kggNUaEmVjX3SsW-P!4873RK`UExbZfnO6n_IKyB@aJG)~s{MKp;ba)RuO4 zA6t#8>rU9xy(R}Rq!3V>NHXdL1k>79$tq77ZdO%nSTc9saSRamUde5? zX`HU{!O^_^0wJSO4gU*YGT-vpqVc+H9bWOX)x3YdTw`_ePcj))4rDH4FS19z8bkOEWV1IMKyhh-e-;sZnRI_ ziZ4*tb={!kv}F$(D#XpWjdnzZ&_c5P$$<*Dn`TwQW&cGR5?i%-7e%T<1~QwVohju+ z5*6R_6aXA=Xty+sYMni2ma0Gp?hKnI`MSc@TtT0~zf}nmYeeH38@vmE>UUPSlZ;M9 z1t1>a!hWju(2s#aI|BdWO?~7K(8vt`bJ8*Y5m+{Y+v_3NM86eX?>H3AKIo+$ds0EF zpq%A*k=o6^m`i@M+c+nuj|b16rM_Fzn+Yn}xPr#KOH|Plu^8_x0pVdg&N_~R8jeC*J>3I7=XxaEZ)c7fnx5U> zK_$8`v@L4he`kOoLNc=^AE;N}Rcb}3SaE3T1K*^f?K?aFSZ3QrLu(~*qt86RH^uxH zVdcpXnSg17c%)ZTSGZh+;dFKl@!_yxON{L-m2-9Ob&!Tn)=91@&t(a50#B_EYV1ji< z_&#s?bjt>-4Ky~xeUPF;fau`P&9WR>NrDO>1Y#_#haRAyUrI>ZkUOIAm&XoG`LSDo z)p#>;`}2VM1SBZAEkJ*R|6e>bjfx0!L)HhF*ZU5qO5DbMx3R`}=~h zG~-Z)Her0OQQ(=M+ev`drq7bCD7^Zi2mNvy?JVO-h1l%$7(VRu69Hg8+Dz0);J5wM zeoGZL2FTZX4aC}17$A*(vH*pWSk0iAS4yTw*JbxgcVZ>`5ZCm~pI)*a%@AzVJfbuxebvJ1B6mR79$n7DMEDm>v8q~XAk}p``x=>%cRJv1n8>>)#8_|9X?3%N_ zqDmiLQPEWz5oH$Zx)p)e#wThJzjHhqA9rD8upE>Ggmd$uVcNl;<$St_8A*sF^+^A7 z=}~hu%j4X4T5THOE@2;LJ9ZJZp`!2JE+i!+lxOHc4tuzhZMVa2+Je_`S_v$yFi(!_ z{cVQA3B4l*1D>A*GCU^CqyUQBHwO%R8(}?qMd0j4$fzxiJgvVH6L60prJcSM|1{g3 zh6akMB&@a6eae>PHGpLiO~M7GKVPN2-1fl!`7Fh*Dps-s?S?NHl0~v9?c@CFXsTSgaqTV)7u8`~!geN(rEzyRP~${ij^e|BgNLqQqQfzL)11Kvp^Pi(kwtkZAB06KPQSxpySTruNlD(qJte(0 z2Xe34cDQs~&I*pu+f@Qm$I8;)EAGdbTkq3f+xauSjB=sd-qbYx{Ec_eQPcXjU~1rd zrD6^aPINXRRY1UsDRuWll2~EzHKLPKQ$HCBR7xQb&VbuJkFfjo!f|+O z+;a2LmVe$v#DH)`cX^#ibs}AGeJ`opVVR#Ul^qcD1yvvND%)E-2^J>E=RoNbQtF4>~tQ6U4uR-0%C2O)#WZR*VT&%}st?-1gn1-uSX#)f4RI^Y&{;1On*M3b*}9%XI|7<*+`VtsmBG*44q7 zue!FVX<5LCXS8CPx0;x9dUD%$1ws@)@&L(26!h%73tc(jVIj7OsYZ_g~7_V3q=fknRG_ZT_R-6 zb4HJgMC@ovRe8tLqCpUK@47#}C&d>&-$S9}-IJapNXi>NFZn&AqL0{N=yJhVa(UP3 zV70c3<%>I3!+Z2+kG!t$GiDmutcn2oFT4P89ppYYwhOX(k|(z>E#cRL+b3G?C9n5= z=VhtXX4j--Wk~h)!LwB%QeK)VZ;5HprdF^KVvFA1XZ)sI0>P=wq_vJ5Dj)|aNc`^U zi8EYbaKPJ=5-D{8noGgdhovYGGJ;iiYi45Ml*@8nH|EXXaj}T0(U64E&~F{{+Z<|j zW{8i4yC9oM*|M2!1}9aeGOo@mC-zjjPoiSfwSjDaNwv|Wiu8NqPYJo-;ZElJ;^S;N z19El~X;v`Azt_aVar^C!Pv+b14bMG|JiLcaMe?}OmN27~w%uMt3x>DO(zdy~Q{vrI zt(eI@BPmvl_O~jYuJzFdFr(7vwJjbaZ$fbIZHM%XzrF%Nr>Y150HDn9bnoB&58b={ z`E=5pW6m9Es?!=de;O-mQq{kNJJPjfuf`MzVb$M0zVIk}Npf(;oKP(K3GPn!RyWjr zs_pZ}NKtR&;`@0}_U%S>(@mTDBFG1|^pnC-y7a#kpotB9jQ=iimigzsorm$E_B-d%ICi}bv?-dO)R7M^xrR~ShbN`ny@gYavh^& z_Y-*yy9=d9i3j0$%Tv@h&#phr7W+~M)bsb5 zncDQRSC@T^mjPdVu4Te8oS_oa1#~u*ihcsSGoGH6-TJEyP8&Am5~^S)a3d==C;jq# z?M-eU3zxySbC8n+tB?QoB}M--3h?7}U)V0nB*Iz}E`CbaT$(@4CDEzH7`dA*+xTG@ zHMvULH_BR0o2AM%`NX2l0SM2t=b zUuzCCwEQe}qu;yts3!huuvi&F^^KIUAfhQNh_V+j4;75}YybUrS{o=QLF8Ir;vdQ> zU8<@-MDN8)p-txoJjjT|lo(G0QzIuC*V11Nq&J%u(;UKmorOL0^L`;*hs6IwgYHR! z2bK?F>5*4pSj{}4jAakO2~jq`T$M?#$Y6(7Hy~O4woRgx z*xOovZbg(`W&QO3yo4Iqf`$+3j$`d({W$dB zCWIg-cDq)jfSE1psT6>cNi7Fy#-~Ka8T4x#>Ge9{K^qv?Y|?sIrZha(!W2U zK;=uhOn%GvlQ}3<0A;Lk7ID9S7fJ{R-x(BBQ(M?-as0e23GkDfBB0-Xj&c9HRAkBR zor=p?C{{y%dR%>&9i8Eou`m}Z`p>HeeHKuIrI`5cFAEWN3Noa()PIpu!T5+zHdXpN%^! zS@^X|@{bFi$gm~Z`~N)Ni`!r21JIPlzqb(`mcC~1`||-vh5gbfbp@d%2fafmAg6;x zLVNqOzZ4C)tkk1^86_k|04~~-xc2z5!y|t f_}{;<$eo3|-l-b#d{_;=1D1x0j&iM{ZPfn(_`sMp diff --git a/test/visual/mpl/graph/references/paulivec.png b/test/visual/mpl/graph/references/paulivec.png index 813a387265b183b700cb17ebb961b41224a2f1a5..0a0912c5cb3da5aae7ed6ca1ef4a57e75994dc28 100644 GIT binary patch delta 43 zcmaFc%J{aGae{}Osg6QMNl8JmmA-y%Vo5G~h%&5PWaws#HyYK0Nh delta 43 zcmZ3yi)ryLrU@Q$hB^uvB_##LR{Hw6i6sR&`6W4-NqYH3>H4?1INCR+?VSSvVxthg diff --git a/test/visual/mpl/graph/references/qubit_color.png b/test/visual/mpl/graph/references/qubit_color.png index c4669adfa79956bbea2676447bfc70dc3bc3fa2b..789e1c71278e046da566c1218faf74211ec203a7 100644 GIT binary patch literal 9581 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 literal 12473 zcmY*=2RPhM@HgS~b_pU%Buca>iKxekPKXlGIW5s0B1+;Ay#*nO66Hvgh~7@`Euu!b z!|8$~oEoR|e$Vg!f8O_fJRW;{yR$R1vopIhAJKX`>aR76BXw3-?!Pl$+!k-#sU zf(+<^-DTnj{*c*fsjCoO5Pq_o3*HkE-6GOdQGDu`ft&Tsc)Bumu`@g{v@z;mHkxaf zBN#*B^Z0G}R|;qCCD9%gOBa}~MhE+$jI$Q2vVeOVSzfDZHm&|huUQO7l-d`46&02H{HZwNs3;BGmu)aO z@vXrj(C!JZlqUj%dmlZr-gllXC&q6CH_189ur$03*2%oZ@EuRleLFlM$`5C6Tf-n*VN!E%^uF86_mPH5o=}D_ z{4HASVas`(UQKWKqySjiUB-_A-avWtRTsQShBDKn!{+;Nk>Pk1MY8o13Y5(~MBAq=4{nF=xh&IUJ(LYj4ow-_N0VVS(U0t;KNzoB5W%2?iE` zCK5NMTRDehsqvfPmG>Ri{^6)==cpp-+A&rTNI@_9hUJY*a$@`mOUqX|bQv`%S}n`>%M;lfV*M!{=*b&WzIg@w1_{*Ur6`u>}H+nt3-p;AB> z8a{W;NXH5w$bHh#?SEr>1$3u>bR}KBm5x5~`+b{Vr1V@OSBc73!HDTQOJrPCs+d;w0mz_;= z((HDhG+-dl=8pG`9=_9F8}gVBz#j*lleZlInDtco!u&AF^KyaRxP_!N>7Sp11MxTH zjvbGCxNZ=vVas{6E09BO(roL46u9K{o<}yvSc!S}TE2GQTxvI%KpOT%ZRn&f&-{zp z)J?^bT(@dfo;_J#lnAH~vE|>FkOslnD-;CT`8mO`294 z@U5rbA}p3T;4(Fu_4Ap5wCl-tGI_QqD~_!* z&B1=_%teO4gZg}n#}5ItUCA9X+R8QcLPoYQrR`X&XTGb3{h-hK1@a;)Di-)D2eFr5 z_lzKL3R2gzk-rm6>rp(*5B2~XyCF9z8D8{fgU^s&p?IP1{vfb+BYrE=E}2Pw-s|?}&QfsK z+lwdVS~H z5veZVY&3LC>L~+HoF|4aP+P8__FWy!x&3ksP|}~z0A=uP$g`a6(dypJ z-+CsaG5lYT-o6*ehC;~iMG_#}3#H;T-Oh$I&d54t;PlAcwm%&2Kb7v{Aea~B$%DNe zCSa$2g_#T^9_;m5UiQ9TT^7A;RCE*scknp~5a|9+OK2r%V~>tm(aCgTSZY)pnUM$B z;&3cx_F?VpixglrIZ?O^N4W0L6Tl&@b-$h?5v&<{4v^YulD~&O{1v&O{Ng=fm~M&p zsXD+;R>6Ij3xfAr>vk>qvfbxI7%MmHv&RWA<(GBbaFlRK740S^EH>zNNhu)mTcD0O zawZ>GTNm<_hBwbpq09kV|Cm58A1!;HOZdXTg(HZ-MM1Z73CX9UU$O*(X2n?eA_HTX zxB|21CE>>aADWl*K>7d8i=Dze?k1Dbz3fa&Pyl4_8ncz((|5_7A)GwjSVQNMG~G=? z94P26_89}TK=0ab1ZwBlJHyOtpny;f*VD1Qv{%THxP&`U5V< znAFZHz0#9X*s}xs5*DheZX0hU*psPq$+8t;$lXE2sTP5kJV3BZZ9j40xF87T@CTJ1 zbUA4pGk7^klQ$2I#d&->It(Q!O%ssqQYVaMHSzY)bKr=8bz?9;&GOLy)Aq&+i&A(~ z-v_jTB+L-7cgbvE_tvhMWgB3~oxl)}x74;2L69c{E${~1DjT6Q zH?_nYuq0YSe-ga$D4js9pqhq`$@r|PqgR1ILB`X39k3yHf(?0%oAqA&*9kEbLLdm1 znRQJF5u*6jm~YQ6@t+UI&8PJ%gSys3k;@kk8OZJ2K{L2k#Aqjy~}%6Lum*6hP1q$tk|OQ?cBu ze2d{?dCI{KX>3GhP|z`9+z3Tz(gQn`JA8g7$t@sKdL*9p?8lGd*PBOcV<*rhs>|=X zqRV~U?A;?Ry=YyhlIjoMI}-xx>tYx!Jv8-bO-xnQ1M8L+pnDnKMwib|+=3nRfj}-k z+}0D97Ub@!4Q#|Fwsk(MIoE8;=WM?`uvwmax|yxzbd)&>k4vBSzRJWG#pjq<7*)6R z(b#&!#6gwJZMqF(#Rt8^T9Y#|00--1Fn$2(Km~Rs^4_-fb;ObbmHt6M}^MGpbQ$2*vGY&X8 zGfWf@Q$#i`%M69EM~oYItd^(@q^xcdeH_I{I1d56oK_WMj`zJ*+mz|sZ#X<-^0{=UZ}N+@%-u!t4~|g}XI(Xst~|S$=Yw zN$RZ7^TG*!YaO)_mUqzd{d;7P<1p;LEB;---`}LQq??%fkKrRDFujFsk(|p|RVonM z=D)X4GNormCUw3@+E8-NQx!@P`Dy_Vy6ZB6-4XEKTl@|8uyFr9LHW{H5uNLDtM%n8gP zq*->_)zO;%JAIzhK+Ok$z&G63^X(rrlm55P?}1){H!~;GA|O&SMS(@7dK4lJ6fnfS z)f9Th_8F$_pGqdJ5;a;Fp*M=^W(?l$YaJ#87gmTxvB5sk#bS7&rJ5uxkgM?mr`Hh& zjm*$L6xn(dYH!~Jo%J`E@>MvI513IQ??yBW%z<4oH1X?pwJWUXqE$Zvm7$NS3!R|t zFzy21w0#gv#d@23wvi?lFmZ-E-CUjSQzQ@%)`7j}ox#j6hpg`?|A0+128!(Gb(^L0CHFpot^sdZC^c@*7}$ zyH<%5h=uIzTMTcmowTQ3%hB0gx^ES&hC9L(=NUO?{cbh5>-@(K7&TYrS`PhelvH0J>ql-y*9390)~XNf%Uit=Co9t zKrqAv`W=y^*52Roj9c#n@l8r8Yi6#QAK$g2Ydx1ZJ=-$U|NZhL_8}1vDVKpaD;}HU zH1=W6Y?1p(?1$@&P4|R$jz8{(giz~NJ6wC>mF4{BT6A0UK}T0K{v?U9=#C(DWR4<< z-?7u-+yOfh*oi`3N!QS|0$x%6-yxjhF^)#J1v+lmgzQZub$3 zJnM9AEf(&A=_ocuJw6^tV=9X8ckiF|2o3)f3cm)pZ={e&c&$TcBa%;)UpjyxLxM%= zRT`U>8_K_RHo4zK3u)QtS~8x*yW;?P^=f-Wd3y|L_O(mgPi!Fb1UC!{6@#$`*$I7~PwAIrC=e8P`t;>C}~-Nn2c`ujl2k}8ZJF=BO(53HIJsLiJzFW zSma(}V?&unhDfAeKqr0pw*A@V^gqZs3^unu{~ZsI$?c^xF;?`vap1N zk^Wn{`|$7hb=q`avjUuoa6m-RY1reSr0~9XxA88oKv*VYlS1!{bKqs~I!($M=r|k< zTrZ}q_jVU{dKb@6iV&LOoQdp!cAM}OXaCYQzPv{1Jq3ZznalEYrA2?_rhhWnY8&dh zP7y9BxB&BOe_fmDskULq4X)c!OMTEcwP05B&2h>AaDY6KDiz()Wrz=T><6tN5O=oX ztahAEQ}zojBp#dMwNiG>J1>kYYlX3+WyQ;#Wx<> z7CCy^E_Mh)h6E8RFS?AeCE3>dnCJwTi7qOt*WLpIbzO~*N)N${*O8Ac9El_$Q%?%_ zyFaV?ux&2b1iX>;u9Q%C{AqHtYPNxw9;HWdGk~$Q;jcNeRL6@9+?Sp7#Lq=?=Iq7N z0_BB6e`xeFlbmgb6(U*Aj|k6!(mkH_HKx5;-X>5MwLV_BB%{yOe(SEe(f(N9Fk_;t zDT??`%d-jBXtO=eshe<4>Uoa*N0NolypkGDUXasGs@JPLM}KUUw0^kjlJdc%qQeGA zCoL)Z(@iS)BIFo!aF$-h5Hs=WQnr4^l?6S`eTFg<^gEbMfp_{WV|0GvHpt3;H6Lv<%w>OAs z4fSsAgmn%jWQrGXAwEflmo3jMyP=Dh_Dd~?N-YbV*?^FuA@`HNX^&3sh^Ofc36Ke;g&D@5XHLyq1++$tdR)&6QHw29}A?Md(Z;?D(@ z9+M&KKZJ1YZn4ai^r8acL4)Bz0m+B;Ixq$ud34r#*uLEtY0qh=?K%IUcv>dvZNjyP6Wo(SyQstYmH@H9rV=OqvJp*Qzczctyu9rJaif^y zX%|m=%N?c}37J=liV1j+6Y2GbB@5u*czJZo5d<9FHXLXl6m+s*1t;THSDI~*3~gAr zl6tQ*gzqYle(*+JgL!%mbdUnclOH9P)CC!~E4d#JAbtH+aaB4pAhoyUsy=SmX@$Qy zEUus%0}H)wRotNa=#}|Zd*;) zS`8HCu3ORQ%7gZoHZTFd-_05Y?x;Fo`unT6!aHNG0bb5pm9&@BonDWg{#~qSM2eM8 zU>vX30%SgTqNpfPm?f-Vg!}m4*Z_=qVd6%)XwUtaA7uM)D)^K;rRPahk_1IiA*u43 zpDs8`U5x8CWvNR6f9kc4Hcgd3EkDa%Re@!>L9Z{Pffwwvb)%x)sY+fvUBYz>YjdjB zy?8^?5-az0W>$%iEP0&Ebt~6iX69+(2<3Z^CPEZ%Hapzjqdw+g*D1P#Catbzj)`F_ zZAO3c@4+@d$h<-iVBIqEsyjDTNVRAg<1ckxfgK9f_&fHmr-d++^jW zu((c#m7G~aavm^*Cyc`qpsXiT+TIo~qR&{Pc`S{8+K<@|`CZh~I2w0#?T8(-7*=Y2 zl5l>;lotH(_@Xjg35CMduU);F?*M%Q`S?-s1V0bwMt;kG?8Y&i5cmwYL_%D*r;{pu z?@!^+Q^b{f%yZGX6GCN^^pE}=qd2Kdqw%d5v;ik~kwZXIJ{p zhbx>CpYPDGVgCLkF)G#wpy86Z_v$`y_W-?1SEX1KdjNM8zxa}%^STb+sEPXr93taD z$j>j4A598g=r)%#NWx#b({Sm$<)Gebr5{W$K>IyNY?7nS7*_CQywsQTs0 zWp(azU%?q3AtnDdM?stQy{zwKX=@&~$v%&LHXQ{<@gI+B;kInNmHF9G@e{uDv`B<) z-UOWhBG)ITqRRFM@bnAvSnf5SU~fxv=nxJ1vvKM%nduqzRDEw19pnM{G7SzoEX^HL zO`pKPZhEWM!|)RBhMk@dB-+CO4XW^&=6Md9j!zQ!_w$v{QLVc7kB-nC=Q)uxY>^t? zxEUw$1E;a#_r0Ga=35{m*}=j_9QQg{x3YZ9;^3A=3Z>)FNV@vgX~@-JAg_$bfb(CE zp4`yvq6QpdzerUA!AYyd?5{VTyk!J7S#713b|&jz%6uum;0qtbEoD;R@ySSqccS7XC-0c+^n&do)f1;50y|_-3*UroNwrqsc^6zyK;^V+8FQbn z?cA94c|Yy+ok2*#dsOe`riBYs*87`VLHYAooZoa)z2#bgLdj&gOZ%0>WzNjFoMM`I znf&7*vPAY(cn!8E4z)NEOoBgoz3+?+y<2;Qn6vfs2Y;0c~RSqwk0X?H#es0}Tux3RSf zQ5C_hFRO^9J|R&9E4+~0n<{Tdi=Cd#?}R!Wdbmt92R6^DUmUx*hz8BQ+9_j;Hc6#r zBeM!Hj9ZMAma1jg^vmJ$BQl!6{rG24Iy^&{@ah#h<7qp0jm2)-FdoNDw~py;l?v?T zz=O9I|NQDhSKfwcz4w^>wq!qy+BF1U=YV2mECR(kI1cc66RQuTj%XqmC+%?LBDH2y zvA=-ZF|zXhy3Z$mztW~rA9otk;@h)r!RY(B4#P2SPkZCTPqq>+puD_B5)bU(W)Vlb zd~O>6GDcoIq2#w1=_>cLdPmJ)G1HmP*S20*wsR|0rVR%iw3pQOAS)iYQWP0u180#z zbiEwL61lL~eH{hGG{^f|GfGgFu=#T|Tq|n4t@Lc$He^bt{#?E7&>-81q}bxPvVXLy z)2awtyclH{dGvV@?qPM+brujUJCmM*rr|K3WBvLH~RDi?P434 z%ur#z^EFHhJ93BFI6rbU!V`=au#txv-cV7i;t zttmUGIXbeEq>|jOO&0A`B4Z0;5J=$MNyRyG66c+-t=WRntg>g8BPufDh5C5sv28WK z=A}n!kir5cd|okXTKC@cgR|bXL>|@=TLN!>$D|*mx&FS5C8s0Gl2u6PY?hmd6}-ed zCZ;&ZW*t4!+A1t1jeEc%maP_aCvp0g&tcP!+Aeviu-Vh5xdw@yijS?Zqb9%4`fNaA zdPxK8%9q^Wz1TQkLl5>;o!Ax-3e|;bLiY+0^e1{r6N}{ZJy6lC-R^?KsM#Tg!e;>*tBdB^E}0ef+VB{i;;z!e;da>2x4qGj3HML25r zcpO|WhO084Rb?v5TW|0?rarqO!ZoKafnb$<8Hjg4PQ|}dj(A$U8oyGvyn)$Yf1hG% zjQ*OqXV)#2G33LF4z1ub2Xd_NLbFHc!uNYs^N6uPx6v-NRM%*IRrocNqnCoRzB)L+ zzE{|Tw$L)uln|A6@vo8I0(#p~zw*Cv&^^-12|PO#su%JaHF>%FtnSxUhd5QCw4j0T zyJ`OfmHo+oPcv7KHMi#7$JYOQ#`1Lp+~-t*U4P3?DQ++Azxrb3nQ=8L+vQ3qx^Vw*&s5#7K8^eCZyEOs{m|dO| zO1i(qDe)m>uTk7dd$y6oTS4?vGuBnN_?#QkW^C{h@Xmc-c<$XE%XXhZ>xD!Q1gB$; zx{{3W$El$@eGk`zx3rH{M(_F@y3WyX$mXI7`nDIhtB~!Kd?rr&Lz!akH-Q4HH~w*Z zB;WblVGNFjh={?KfCWeyy0BXcCeJoEKXLMN6g_*8;ex`Uydgplu;9XvOIvGRQ_q2{ zO}_u9TtW8L7D#gWx0XFlFXdMw1=na~N3%e`j9cGWjNWCfnN@v1=)*cuHS*I{y$iV% zscUolA1?jlcA7j+2zr*!q=i=G>CS`hQ*E%JM_?mW%CCLZlE)nZQ(L*}{w3f9=P@k5 z2^YxFfMqqW;c7|BFBlLoimK#}Z;$bBZ!tY)ZEM?<>6Bl9!FuBv* zwP^6f76K75d3Sz8PnxFpCN*aeP0qK2L7$D_VWT#_Sew0}anX5HTKGsgY~))s^)iz> z3K!upAI`*fjZ^9?xrHn%>v-Ql9Z(v*8cE-l{}`q5vY&Zv!o83xJo_;l7T)NF&5d-Q zwyDZ7)v`G_AD=Jv5|S>JqS&N3;IesT|)$Xy~4 zj}_1MnDhxbT_C~A+z0*SFFu}D`dzi+G1A^J`6Gn*_tejj-;Fc|c%D3=(n5D`OUH{3vyH|sK*V@gia2M)waqH%a?e{c~f5t=w$b4U%|({@Y>@9HqP+SN<@mv~tX z8)OGAY<@zGe9@m`PSJe)EnLskbk|5O_|4$U&-!)0xz?kA(!&Hh$_sMP-lUXjP9Y?f z7Z_L-A(qQWvqj?esa~PQ!WfEus4yp7?*cH?y*;{N-<+H`u4;81fVoHF&+6BvXJI$gG=t}bpq@tvdHxC zsnJtXA>)n)Zzl8SQa~x#+INfY=%}7i1{8+Z_WFmXjkLMdD(!=e0{e6wGQ- z-X;rjh&TJ0WS+xeQy)OzlAosx`}AZ`cmq00bRNw@icmyuyz14r6f!#jvikjKh|p7h zff_m*FY0U6_@n(YT(Wu7Bh+WEMx4=<%-YlS;W4K(3!U_H$hpLEzIyS8od`*Z^&H@| z)&b@82hMX8L+q}c={}PKcRr$_=DzJ%q*CMXeD*6C>=b>(LqJu&QGtU%I{H-TTCkm82;pM?_d)1m!x4!&b${D zB`ScZkBK+2c3FWCri_74n+b+65U=)U( zxq|M(0;6D6u))o?nApWx-^DEdN(dd80CpgkD5Wo8Cn<0}C*m?~STUMP;>DK>cGFFA zaqV=O4e`S&>;cd7*0{etwEPQe%@P-vCqJUe^E~XTPNr;NlVuZrbMb{sA+O3bV0+_C!U#cKv;2jQN9O#M%+H|PDq(HkO?a7h) zD=VotDOTrr%$#56l!VqJR~jxZktc_KvnweM2lcwkJs!t@ru>7zJG|aC_y&!xtg~W^ zw4>2=Jqma;(`Fra)s_%fOTl&@DCmgV;-$WQEIp9oD1%jzeUcoUIf>CI$;QI#tp`|G zWbRj$_*^0OTObAj<>GLAXua*S+HVX!enayDSL?wtBsUgwbzJ+Y%IHIJq{Yt``KI%R zl3Gm%ph!N_43WEN3Q<=XRa<JljVaww17j|Ip?Wt&dgit4+WI8R9y6IXkIE+sxf7 z1V%DWlS0RZrqr928*%H;pBwRBr!kwDNxdf)DED$R1NSplLpXPPC&vnE)HAmfW2!A5 zQ}^}UB7W<7HJow^ZY0Q610&!G4mkMF@VF`x#&^C;9=|{45l2U{s|_O%`CmzY*cL06 zn7=!!h>Gg^vb~c=qFSL~MSzjq{Jgz$12EBFSHcs9*`ES8JvzO^L+z%tgsh{es1$w# z;*QbbFHp{{&_=-Cc?fe&7QdLoxt0L%95Q-;K)rTGrOSm83Iz}nglc#hfNpq8Ks1Q} zblw6rx);G6y$-hFm-H|IJ%A$>p6i5$H~{hi0aOSz{L9h*J58gh83Cl`2upD4tGj^v znEv0!Pqi0ZNdT-13Lq>JEpoPZ5&?Knh~jq)4485c7#WSh2){eZ0oVn!29{uAx*P=- z7WQqXn&6Y_}~gp&~+3Agy98*iE2#I4YcpQ&9xNP(aTqzm=X2s>i_qBZHjI% zAZQf100O~f?;DE1t#EVA0i05LOEDx`0Q*7dUCsPIjsNYL^||(6&;K@}Qzziw_Z8^C zU_O8~@E$514V16d0h&sUsWBQNz%GPICjB=lcFn zZEPW7tBrxF3vD@*NX!6$IRhLPNd>$SL^9nEe9{6w?U=0-WZV%9PoV!=_%-SmE70hg z)=>mh2Fu^xA->cqU?0Q;Ya)DksS?5xdhNmg^$^OU1QU2j(D(n_cwrHZ-vuYK=Wh3T z?w|}t0L$39AFdle25e~(pnDk|!p87_z!7Um;IQOc$$CwWQn%IgAI;UaSV%D{DwqQT zfc^(06Nz#SPJx987+BBA@e74oGwkm2_m%Yq%f`ttd>amKc>KG;1wg^*gzhXaz7@Zf zixdY?bd1n?>oEfM6R7q@sR_T#ICZBE&#q>a^$CM)5>oUXk5qX20dIIvpwPaLQPzwO zc&dKOnv;aA?N{GOV{M}yBUm%Bqqm6eW|-&l!agQ*@I?ki_yz!SS^OM3Q=cEDAptmQ z$1NC;4LaNqZ*(&^Ze zD8Pw_z{&;|uI+n$d=>6h0sBnV?#M${US5x}$J+~`I|-De3rA~iKD=B>Hm{F2BrsO= zoIx3VRJAK*3XFhy&RD-?8e2Z<9N$?_w~(qE0r$dK}6H9 z<^xys``N?q7WX;-+M= zurNzf*7gWESPtz25Bqp0m}RvuQg7vL(#5^roYi znpq@FHFky?xfL`Y7^h-Al<})q{R>cp*leneiURCeG*xy&aD2w&r>e({C;qrBDBKO3 zgaj(OGxg_Aj&UmcWyv?`Ju0ujVm^yEx5h_b9X z`Pf_1_3M=M<&bCQrfD_fg{89I3xiTNzx7VeGJQLg=?&f4bp)3IU?~tvP`fy~Z`|yt z&msC>HV#@(IJ7fN&O9AEWx#z5;kqbLs9r7n@7l`BRL6MLFlt_5SHl@ZR?+kGtN#A* zb+9JjSE*%vv~hqdxQPO~02?-`KXk6K!wDXvH zjz12+zHo8Y`bks|KurgpIs4Fp!I6M%0Ttq*P5>{p$fr<&DQlrpI8+?$uWo--(jUvL zqB5#&F6h^uEId+bxywKqp0u^+RhRA_ak8luI9oMT`Ar6#NHa3fOKnygVW2w*t1&e- zU5Z-+gv?J%Fh(5a%m(&X1H}f~WKrFgly|_b;@@nKkXn4$&o8qsVt=3V*bXN$%5fzr zeme5gw7E^gLKI2&eD$ou21wf+p3IBy1#)p+pvCMz`Il+n2fLt$!<DZ`7Y@zqWq?df8ZI_4!g${x4;-+q zR23D_9{>9kbeE^0p)sN65u`|QMaxy8AdV?5N##~Xv9w6m~C zE1h4L0!H@Q*g#a~LsXpGEuHR?tSPfinXCpS;U6OZ71NE5d3opzlp;So;m%U=MY@4p z(?X)z3coGIBn^(v>#)k;&OLC)ZTj05%6^kW7iRLn^+i>wePKX8G`J=ybjF2Sr3d#`TSw zyh5{=)Vcus-+vHiZEe5F)s52uPXCijQD?B*0!3SBVVA+WY`HUi!wnkBCnKgmPBF8e{$I6osQ;uJ3`j7PYX3jN8~WW6#ji_LI>e%`=VN3&*uwKAj!W z($D#Fc;Pj#fkbBrV*RSF|5e%BQc8^hYwk5X!m^>{b{>D(yTo%375CXHZ_wv}z5ZD)$@QWLA*;{4#?1H8@8J`}qj!4`!~Xf^QcTheA>y<2MJ$Pz6uhaq zIc=>~w3{_K`?2}V88dkU(A!Hg3}bGe7`OKaTZQbo(s!MATd5BzF7(KAzL>{b7;Hc< zisCiH)T=gdOa|Krz;(}n)QHB#KZx`)_&_KX>1T3kE>=Wt^Ui@ihk`y%_D z+zC`|*4AK7iGPA3DL;~mL|)?^m2d%0fn?;wTgmpr*&o?#YR^i;l_)@w6O;Mt-urgk z1eDVUpB%4PfF(`KMQ@#QpT?0IuLwXod60s(idwK#+vwy;li(KgGb#(Yr zJk>K}2G9rvHBR*9F=u+k`WxOIonixqU4J8SF^r!i&#K!uiRZ(le{dI}=!}j{`4_s) z6k`>j$mfa^U*?R;%KNXf25PL9-3{L?DR>f$O+V$jsCMUfP&hkcsEl#!(ahv&PvER7 z=+SPmwN-l8HGrDGvs>+(Hj9L_GfQ_q2KcW=<7Qk{RYtF3kE&!X$A1WBnQsDjX~&GrQNyCTQBiwehhn0Cx7T z&I2Q;T{EOrJnemtf2utrgfZ(a`u&-;YaK&{W5nallP|qLd^*ulr!L+{$H#;7I);>8 zop_ro9K9py?E@~c!q*oPw)yq}28{af&!U;8qJq~LYF=~wUCdxg#-!*=CeQnPbX zBqmS$;@#)2-b|{l)-iuvzZEdvgEmTjKGx^P->|*@h>j_bOb>f|F=&B88J(O^1cCaD zv~XAp<{{WzWvsNo4{mxJ*s|Jgs1iW4?x}vZR?PBRSG#(hw4G;>Ob?x$zNeX$$R@_2 zcxV6SREHR6rD5l;uV~7={Hy;j9Y{B5YCA`AiE=K@odW9pZTaayv^q#Hwa)R*G8P1^ z(cBErx`+X$wkg-oqh~{IFK~ZG^=+?AjbQRXY`ym~Os#KR+BhT)XOv$Wp@S9#%+W@_ zM}6pK4YMC$fW*0?$g`{g1MMI&W zFJCFqFZjZAzDLsVbt?qC8Om3P8E6=4=hJ51i1~2lxul&fDf?FZmMZ2BzR2VrS>fy^ zwfK6~Vr8=3(^{7z%ncAN0>IC5lCaNiBGGHR5M*u^NuX(p=T zn~a8L^_L(|HEUbia-u!!mG!;5vMY=!QJ2hr`#mPOtyZjl3#q^GB0k!ijm;<_w=92Y zax@hy?+*XRK4Ey@`(XTL^l{tUzls==j#4^8LUTALqU;O?qVA9P0*Q>zWc&jnxnFZU zu*gw(Yv--kzgc=E#3_zm8^mVi*oGUJ)bA>lJYAOP^hjrxUKwzs({9;ag+}oyLb~%! z&=AEV(x~KQU**Q=4gHOgy@_I8JxK4kBiL!3#IdFGa2`z5xdLTd?NZ+FQJ91@2(F9$ zeb_agfDO6CCMM4bu0~-jzJgjXLx~zeU%{jO;z30=4Qi?=e#$Fu%iVH`s8{l%ssmxDdUBk6NkPxrc*yK)X8!!U8mLN-ZjUt|DSSjj5A(DUap06%_5 zbjjJ2jqs+oijHz>A8Ih^69iXd@)$PiWM)QF1o%E1GG$Vjsg=pg*5J~r&#VY=2cfQA z+8zY_n|DVY44Z`m;FCTc%wl+~T=LxCog?0G^cXBOpRP;|@|-g+p>EC+ukNOM;iL== z(JsfR7b;6+&++GySupNY$r%C}xS~T*80#<035{2%J(yjj7%jhPJjgMMdguo@{rr17 ztW>yT8!JPov@FNKC#xFai;&|f+oq!9Srr`a>nA5A>`ciEH8-nwJD@||jV~v@AoSJG zdw;eY(6LqGpks5Im2y5e%y%H^3kvPU}2 zy}GX4LPmwH2JJ)j+Z4apQSC76x+_;5gsrL?*jb_$Az?f zz}|(+?yD_sxtK+#v^I36SH@+kwMQ+np1@{kzooq%y78-tOr-+X$~K|e<(U|dS;w!v zeviVDyI&^Gq0%14yQ)c>tOR)EQBd=DEzbMZbNZ~ckvf3WzFgnFauc}h*QzG7RW}NkE`!o#K{JmXinAuZuXCIs-P>8E7PGl zjLpm?0ek8xFF- zHI_Iem;V_{bSmB8WhNG1jSB+a=E`>ym;rPWiE|X)^^9aH;`b3z*t19Smloq`|61D5 zFfRo}e2c3Yzti)D=&$4mycO5NXK;2vXjsx1pKoXmX22fRKwXWpOiPTH zx~P9_W8?Y_9uoKGSKA)5df=#%KQj$I4~&H>uNS<@itD}VuzL>m3 zGnWkNl-Oh64~IFH#B<27-7IM&N%lzS6BZBAGMcb2^)Qzzpx6B|j&1lip8QUzx2IEq zdlUBP=6o@x>6h}HRKeciyX4@`Q{Fs7WljhLMw;&wZLpM_>@5{x8KXMJtjZ#;`IisE zgP%;1#}~>}zpeqfkQfl!X{%O?)$g+VAbO;msyH6UG?+41_nyEBlDacBbD)DcnK_^B zZ}h{aSz*oAwr{%kTc%@gaS?8Dz4CxDNp7;rYr86&&kix=fBK|S&8y1H#_=NlU3^8d z;b^GK)e5K<@c1bhTp4=^Ne*sjnQgyDcidnUaO=*9-z<^v?X<4 zjW$&OJJ+8BAXk99$hc5W=2NtHH$AzeQx6HG@YT|08BGw(-Pq2Bedl_Rfu=CtpCKFS zQ`W9B2hBkG`}7qYZyAkisz_Q{TA#rrfHR978L+63$6Xo5F=$aYH5xX+`i0OZb0Nf% zrZf=1@UafXmN6fhxAr=lz$FMR?Y0PXZjTBAGXzJ@IOwqe0QvspxoOe>|x-s4Yls=dycb{sK-?!SQOF&HMh8hZ8>u$eLkA_xp+pm5{*nDFFN? z+v_FiyQ+qm{O^nuxQrbD%GygLp+!Zf*%dVmCJPtEo&Rr4HUGb{(vz8nkcvaatHI_o zGZilnfl`5k5zDU{rJ%Y)-1F~gSGE~H+_am;G*?wgsP{R^c;}??Uj^P2(GY6yO9k4Yf!6IZ^NIc^%UM@HFYfrISaJh>bXF z=}g!ochQitdL50RY_vxu=(oY1fV%9pS9Bu>XVuo%k9GI_lXN%+nz14DYncMWhgWic zAukP>!#jLF*@*T2Q@OUHnip=7tSO^!p$q5Y^}ae$VFfr-VyOR&rq~}{vLWB^-phLPGoj>AC8c`ZTSl<33Pra^pm|BQ_@!B1L=cyi$pLu%C zox(L+;g04C(!)Z?c`_+=2zGWsJfi(VfZRg`W*J3k-ye`kFY$OXO323t+fB*K zlT+-(1piF*Z<7Cc`Bi{Du0+$2jJM_tJ)|XAcHkP)xM; zoKzn{Ezi5vw3W%1KWS zzA`U*AY9hP6|2|A*hpjY_TTQm0`fOo9DkU2KfFs#WW5qz76GU*Vd(3<6=ENZ8fqLy zRWdHgV*k@w`h$_Q1Zke%!XPgwTc_2hE&{{><8}{$^;e2{+h$L3l~9*gCvLnt)q{zv zkXP^agQ(@YJGDc6Js+Oo_VsO^{?1L#`n4UaL)Was5_=Jd^!;i(CN$F|8ufhplNcp^ zo9wzQ#T8IcQ-GA);9T~7`vDYN0k<~h%BOL+D*YCvNN{M*fOC&@qi_U0P&&}Eth0|oWOT!;sBUf?@Fk(aq;!_SOZhml>6@sHPY5IxA`OH z7rGQuZ0tJY!I6!>k_Q90{sOlX({N#+`n<(Oq?bSoJb8{d8NLT|t7FA`6!5Hx4g*fn zS_>aX3Q<94YjfmU+UIC=@_HZmgmr~^btxpnkQiT7F>BX0ys;qn@vx%kt$C9#mElF? zW3F+CnOh3Uh<0*7n@TMeqQ$b7uT#A9yv-5CC2mooofGS{!XH&`Gj$#(I#(_Lfx_hjf1S2Q#K zNt)?ZO1_i6X5as-a*}8hQ5m!rww`$Peq5~7qk};xt?Nsxz3c>CV0k@x=iz*a@S?P1 zP!mbE!1?VlS+>x6uIDWtu!KNw$h$7C7GO12C>D7YK=Znc4E`IVhJG&K_<`QOBrb)HZal?(^{SNL<=9jrGPSbVJSH}m-LbM5b9 zauxf$lysB1xm9=RBqbvO8Bod!QNP38-=YYI0^(uTx#p&@^Om33A8FntsgT$2V}ODl zFZA1-v2=Qv_`_c~qXcvPVI@aUc)~Jk2Ms(-XAfZa1Q)0K#O|TeCOpUNr0o>JMNfR5 zMP7-MSpU_85$v~?Np6Q+X)XK{v}cNdLWRSF$(U@F(gw_!`3h_IAw-*mXdZpDG@5fYQvM1G8 z!f$ADes_!|T3s(mkMWN>UxC)5zC|O=5eMt-&E= zx7c>DbhRxL9hag;++3k;ClxtaqV3qh1_49A`TG1r4~-_0Ii!b{Ns0Z5(7{iNkdEl_m}bDAMHO6XtvmUKUS^oynJcZhY`0`H8$f5D6ooZG{i&Y zjLVTp^-W>_I1S;@WfLa8WT)ppqhe&r62dqAr}hG^O-mT9-1R5bqN%M}YJv=<+m9my zUK-+`I7g*6wA|5(be%bzdlfe%T~hQEmJmK5f7Nt`e1gb-@#9{-Cs1G{kB09&6`*+K zPZ@G%WixWc7fQWf4OXX6-GhJg{8CHZ#G)&TY72uvK0KhX_kK2&pFV}-^d-x+=X7jq zFWSUniRCE+iWmn164lleW|;pmbG<;_5?*Hb1$0QuD*3zY-fB?7oZ#ba-%@R6-o@tO zR{f)WpxTdAm}cv=x5gAum#JGPqs&8-QHP(Rz;OC*^2FQ}%h^0K>axN2x=#4xB}@GM zKG}+c+tt?(yQ9t{GS8dGvNtH9u)6FVg(`!CJ}_1T{`Ai0n7)09mmgAK4E91D@!Jd~6F zSq(M6Wxp<1jQ^~0@;tNsiBeR`M|K59i8$ojgnwdlPc{SAh!2>_PrgBUjL6`Suj!Xj znr%RM+MHYDSkxHq-LDS_Sz0i(-5pFFnI{u84v!Jo@IE!pST&t}(`VYHm{dz)XyK}bM`k|CB2RYP`k=C z7#dTs|1exnbK`c=gh`ZN5|5`8LNk;PyBko9tE(dc_fvn1R!2_K@P(s+1r5y#tvMZS zVjC*)8Uzb{YwqCLhG2;jF_QqQsAZZyT%5Hyam?HJX`cbrugtA`ws6gpED*DFoh1Wm z_hXG}mNnW(0_4d_5=sqdAqs);vOCIKMN&p7^$)z0mbRa!K(;`$rd_2K`3|15lD#A_ zq84zC5jEzsBm_mC+ys?-{!Q<4YJ0rhX&oVQ$y*SHmxn=)f6qAa1C!S>!l(^JqE>>J zhO#BQXkQeFa(8f#bw@rYAZ(pZ=!t_BeYVEnt4{5pKu&^xJ_dOCPLhkJ+LWHYaJn9r zv%6Ek1wlpk;!LM30Z#t#Or)7j@L7-VXD~@OWt2mVwN)Sx$D&TO&0h2#lP4N z9Oz#1;?3}Od?Ec_z^W~47r+c`h*0FF8*Y7zX2~EJ9h|jK9BQ)v>vUw!NV)Hy#&WzB znZz`mm4y}h_&skrjCEQHzt6#~l&oV6e@B(skqEjwLw(0O~6%qp1v(r!8pQ zYv60&x9dt2@p6mHi9Z+3xIL9Zu-5RDPmNzWd`j7Dj+*(x$<9%;B{%{vqE02_pa(F% zN0Zv{pzy`9SVvCTxzIj3wTS=I^Pf25oTaHV^&T%x@r1q4p6%Jl=D!+?26=?5&Ch6e z+n8ECy8GQ~Zbu%JWh^!@#=Js5qnD%p-vZvQY;~VRANhiHRsbj)5_0BxcCZ#Eu>T zH`gQ>O>m|;ouO=>;UTE`%dcEwS^d#n8yt~w5gB4eADZqE2U!1s9fbIDw&P(;#P1J~lQ)CY_a44h;WkF zH?djCKv23b;)fdbDO%2d2#B@4pWF3a?h-Z=O@RW^2eq^Z``h3DozYCcoSIot+uo}( zwU3#_25jcdz1R;en9R`7p0NM-E`XPSE{D`op(ySJsYd;Z#-7%?JoG6}88T5-(Wn$f zx5{_cXnFt3&L77!i+AGl{KuJEA>szXji=CxiWr?AKh}4ham2IL?Ce-JiA#AnVK0AY zolGeNy2cJVCNbb&ag%l`_>}4X=?bb|=4qjXN^i=TN_NS7jNdM($9p)Swqx&09DtgX zr{DlvoDTGuZqfOJrj!y5qtae@({%* zc%>7N(F{CPcx5a*fxeX@6!}73c3GQSzDkl6*e{{pXW7?E_THojQ4tpz*@SEFO3L2r;wEHY5!br@ z=lcGh=l}fwkH_QqocEk}p7(vv`e3a^q!IbhizoQ8;g~IwY}Z8iNxmmDyPNaB%a}uZrcr6So2BkdrC)3OUu<%$Qd3V z|As3jIX)hvi{ger+ROO=;X$F#81*_)fzrNogOU-O$~sa9oA@Dt;f5Rdnu83A5IQF{ zz3v}6)xM-#@=o|~G<}F)a*&VpcJ|jWY0_CFl_H@$@rUdYZy$HZ&AG*ObH>IOA*2lZ5qDrY4b~AX@K%|fORks?H zVA)gQ49<)i7FYK_NbB>m+2F^dvE^!|->njeF~r2HU*A%syuiqRaN9V8@nxG(lKhMH zm?uNJw1&8?v!|OSs`qioQYS0YII_0UaEAM{A9BTbT+p#*wS|TB!2trz(wb|WLHMj$ zt>!LTH*><KgmeMNpMD(&4J9M$Sbm@Sb_0MnNW2(@rbIBY0`oXGI0~HKEO?+N(h%=2#>r{O+W( z*8GKQ;=>>gFu}+M<8~^#+0eq=8L72>l)xi@V6xFG(`g-w|BWi5X4#mGjA7l+N((I&xenMwHJYlj!YS3W6zm&nt zWFCSGt7DK-`1T6|x%AEzB)T7C11RgG$n z#bbr6OjfHGK7}}g)O7f*>N&vx-#wQ`$H60JUAU?QIB}1lM2cFO?i!(dCsz22+ zFvDrSWJ42^IAl5%Wk;glA9Le;DY;T)L5jx@H`jz!K(YCm5u24?QN`P7S_=40O(7?s z;3IuCrBm91Cb@%%G&#UHb{p^Qs|eC6V>D3$?m!ea5nGwyS5?(q(~@6kno4MTtQj)( z=<)dVu6*2qnl&aBtBRhOgIViBoZ~v|e@P$GdfRptdiGHMvDzH+zo`UJlhr*bUP9{l znynX;4*K-ydeK?>+0wGkEHi@cVgg4g4mG& z+!Wu~hehvor%&U0pNAio)W=76_r)ezmsJ{}qtgMADmNzji-TTWEMN5iqTyjMh)oup zQPBdXmFKA`0awRKm%pHS?c;krf1m;$hUY_kW|ufix{I^A`RXpm&1>``IAU8RUJa+_ zcRA4@_sK+n4H8*3?~s`JQi%OGMvr_pzuX0FfZWATH;a3Z6VopAg@WQE#={#ZoS*45 zbj|*Q!@5+`FB^#4-Cw|blRsER2hbEzY~S#|$tv>$9KmPjMPAI z_a&$=f-KWqHq`RyfBzRv%8pz*GJwFz03gUMbg2M`G&&ncgvi8ab9-VV;}a#Oy(HWR zoeH0P4IIiMs-pkaY0XUOd?m>%#_4XXpDzZ6gd?23x#?9^SrM?unqf7L-)V|>b z%ec`ope6%HjTW2sN1Re33IP{|I5Ca(^EKlrFmb7%x5S|luAfX0#VyXrK<57k+wOh| ztL)-lv*5n%yh=}n1LOgKcW{6P&6Bd3$IvJo0s%`k*K{+r|HeQT{V|y?7rl^$OUGRZ zt1u)?y11VL(FY7%FPvZgXczVUa$HicTZd!*^*HkSERG&^fzxK^8IjxnjmptZ0ZtT8t@YG-$#xLM#Ypo9HSbHij@@gmS*LJUG#vuuxL zO-{twrCqYrIj-k4qP;4gEV?G#x2JS?85Q%k>wBW+ZP;Es*giO2y*rf#^_7uHnJipB zl>Dm&#V4%?ok$8BZMlW#I)GqUkp#6v(M8X*C?}Y4@C+9I`FkT)Ma0s;4usPD? zbMnk(j<=KKC_Hc8PQs~r;#49W=`Y;(IWfi7_io$%bhq;6Xne{Oyv@|2#M4!Lp$#!G z3ff$f6Epd0CLT$; z^n|&gl0%})#3bj}OQCdH5z;71xk(!KTtwbq zK^|*Bt>5Tfc`>XZXEhZMlP69U!9ww@6X<2UxW=O54tK!D&@$JR}#c&VIPRju0B8cPVd{XTH)h4M8Go3rF*9{PHw4?-F)o}{jF-hg&t=3 zA9;`p%qLqn?2HzQHgL|;RJIbWYDc?g5);1w1|om7!;9&1#ol3btI~Qj_t(On*g}?E z6n@3Fs0L~fv@4(VTvg^NSd7r;{CvqWG+!$Kr?s-hq=<-5@MiUoxzj%`-chNBS z3`RBm^WV>0{_X3JjK^nE@#g(>d(Zys&`uj8!Dwd5hESlgrq`0v59lG%kKU`3hWB+7hNsJ z*&LGN0@89llJhAIaRwQ|%35)DJWyZqw%Mg+TH(5N(x~qeHs*0R)njyZz+K_f=^u6b zO{6Q*w`|`H#5%mBnp~aX$1N;wYaz?AatQJqEh!Brx|+P^%T-isN8Qg#L$mPuB(0D>n8CFgrbNS#c(>C?ZDw#28kua`E?bx*c;fzSQch@Wx?)=Xrm((0CF& zcEa4|IB+_Mr(^AKi(I0&yH(4^O(|iTb5$Z|3em=d_E?Uw+586Q`&!>7V^A{DEXS_V;;jpSd?h z`T3Vfr?JX2gm6iro&&I+^`-A*6xlv-hfs^EN_3pDxxlj<;O?Q*;@0FkMB4%%A1AOB z%(K>G8SizFU5=fN9X5~-9Cc9nsfdV74E|K8hs)cK+n@v)zxDN(q!DjdDfYdU9!UzO zYP4L`+kH&WTnjQQH9KJe_J@Z!S}E>`(W7w)ov+3|*1zSFtF%o1SwaVm@}zyurrWg|>~r%J z(rMUW7uI4g`aD$My3vl#LcC_5&5aRk@CW0JIi@qI71>`7^o^0Ls^f}H?Z|C7knyC< zF{kF*u6F6MNbc~g&V6p#7+5+G?^?Fsf&f&%tYczmt%mGl()D{EymV~{5+l*EzYCm z3>kE={VM&W&!;^4Ol!)K=6X!Bdi08!{w@0gAAbFN_tv-MiG=QS{?PF}frSnY6c*}f z%}1_{MSWG6AM&voc|J#&0rF&?$PK+7u~5=7ghS{Da`MPx6OoV{GrJg?Q1*>AJnN=D za^6wJ2Y?=qJ|1CfM@DVO+l&l0O1V2HFEg!4W@-!{V=bJt;N1Vv+ty5uFV~-!M0mb+Xu-;3Wp6;FNomR}SMRQLAZuzU zyM3r`zk=VzTC?Ob$Pc6Eb}7gwpIRA|l!vn!>0b>zMjTulrl95;@;Dw8N+MhgzV0LO z2(TOm znSjTxEq?avcz^JzJ`5wsACGu05+Z2l3kyJS{q++ICw@D-ORwSorzR=++TAa@uQ_jAb#qI-`;LhLHjJ=e@o zcYGLv|4k;Ly!WpA|EBi$z1G@6-0TZ(PIKjQ%oi)|NqmDR;|N_SdHq^EBg57-{Md^y z(DYtcv@Q0fR%9V!R&c&Dli=b+aI1fG1j5`fR9o0q$Thb{^{RQ9L2-Sw*6)cWcw^k0!cmf7<@c*&6bz4l>*Zc?kh* z%pEh6<%`hdU5=fGIofcAeY=U$4{JtGeJVlhOzanT`dLRt_1dEB(Q6G|i`eNyh&`QN z=N>~c@V7+62_$p;nH9OYuFQ>3a?WjrkKISD3^`9DMx9}ZpjRFhwWn%$7g$c=Ob4x& z8Eg`-MjOf$#hn_JA-yGS!zM$+(J-czWxi!;dt}BkPWphR?o=ekNrd0uLEyuWyxb)U z;{fl{0;r)di6rwO>wt(S`cI6t_u#o+<%&y5Mg%y!&O8zS;Ine=G)gt86YpHv)_#$l z#!X@O6_MLO1!>zy$I|}&8PlKBtEm4FA6XI7$N3%V@vh_-k+c4V8D#!QOl)Z(MeDma$(zPAy@x9GtdHmu*j$pri*c^qCp_>rikZ9Dlsh}9XpoQG} zLD38|NV>V7<$QC%%y?8(v}HN|sblsQ;c0))q0NAvOf^C*E7HJw#_2+YQWw(BC8l{K?fVYk4? z(ss{9dIs;vnsnDa+A*VE#IZoayS!duJ*VhqoBEyQxY-c6cCRZ#+NKHKq>;~APPf{R zg+3BFR83xuKc74=9eVJ=G(zb#CmX*Fmf)5z%b*@1Xm`txPWb#&WAWRfH0{~*0wV@R zgUM74Oh*SIL`wC%H=t7ZpMLC8LX+n|BUgI^OVckk>ZVQZvS;oU7gIjriV8L-)8mWA z7|o1DMt4qFw2uo)h@+`BWQ>(4$+ z;hyDM%ThflttY01{CX6;N7UMuw_NFwVwWj3C@2=z$U>()+7qNKKGn<>e4aGFW9hQW zZSTBXIX~DM;6fIB3`fa{6=AUxhHfI~9-%}R+X7_9Vt$O-JtpFT2zK(;&iiBO!ChJ4Efz4y}K!P>yyNs zjnts5R)i>PKp<&;7^Pa$)>?T^$_E0~Twj1pVCa%AyDjTbge4Cf5z<`adfn^`&^N%vCK+}_aWp^&QtXUD#{ z>FbQ={6UPFh-tRm2=@K9@$!`iD653vjY`tQ7TUDF*oQB#WJa;7G`bx*p#qI`{B_IUH3Ssq=7?htgtl3rnuWP&XQ${#<}mA?429w8 z4<}v|>9^eZwOd#mUQWn1yjl4D5K&WUqW#K;+*HYdLUj#8OEE;6ebK+xH6L0;^AGI(q82_7j%##Mv)Yiss z6+U=aT?H~~*~8O>otau{&lB0Ynz)s3bS^sRJ(sb4%(LWD}{Gh>2l|aD-bzmCisFajuP52;%|A# z7iz4D_d0gauZCQ&>ArBCcntib2yD>Ul6YVM+aGDcT$x4fXJvZknm}YaiI(vpY5(`! zE3)`ee?3)T*m>Lx&2_py4TUQ%}TSr#>ySk&`(6iY3grguDXn%|lpLvIHO7M7g zbw>l6AGoNzNtvt?v0Qr<`@kQ?0d7G;SO4^P;P=*OHU}|v)`=f0S@Ucd#1556px^3c zxbIu`$EbDW|03+u*@Uglta#oTn$hKrOX_hgLm^)cPur!xUr$=_b)qPZ2(cNFl$)qy zsraLsf88F_+QgJ&l^HOD+99r9GB^!^kkKgkqK+&{cN#~r_>UjW#OZog}6XpnRE*`dPCzN*@rq`3${CXUJ~2EvN$TUWH#lTQfa+ zdCHA9wQv04k@Md~Mzka;CB`jchEXvJ#E^K^|kZV?{!H_e{th`ob zku&C%YX1FNj+8&@*A!zm4D35{oLkYGRIl_6(@!_qWkB%;=sWa47B&h~YMq&Hy zA~C_|x}PemLll)PJ}fRh?!%5Lq0I@M5nRw!SCwVh}`oZziq_(;_A$&m3C ziMb|6{QhCU-nfDL?T`c0>CX*~j#*ECNe|c0?r=m%UCZ_r?{9$?D?J!N1!ir-7SfKr zz`a;u>XSsBIzs^^d}^xG+v9j{cby82fDT3Ag$^&lY)DGV z?O<>(2|FNs~a{tC)gjc=`+Ef6eYTY=JB}d-{dqTjx65WxRZKg5r9Ea9$6M8nHeKFEBK)g- z5c>xPoBBDrLzS{FW(Dl_R9w}kN*AY1zlikv>+vu@ht`z1HF#}LLn-o(?yfB|O!(NG z-J-}}f0EmLyJJnuB`#^MExRIfJ6@etCWdC3@{gR@EZqm=o70sPJ*PcW?gMV$(lj<7 z_6ptYj+4v1IYdnbJm@-qV=zRU(>ag-ScAuAkJaDVepMnb(6>G^(wX`6?j2gPj1N7e zu*vUuUUE_0HH?&u3R=p_v>xT2apONyVmV zzww>z;AhwOmmQK~f|zGPS=^xgFFE`%X_D!cwvMkEmA^DTXXMKyonO@>sO{|%dE2Af zCMUJp$}UIjis&w_sCKi)4(*O{T-Lg5Y`AuNnSH?-WHx@9<94{^k`8<8jNpbmza4DG zp+vmv9!rCmNtvmT$eVnxvPscv!6Gx9VY;f#j}%BdO`3%{tvo2}{$cFu3J*vd_hKtY zFUKW{$%`s50%I&_i|k$t7V&BsvGB`x6I1iKd9Y1J7-+^Ed3`3}%41mg5yIq#s-mdV zwuJb*yZvlg+w6t053;g-x9v`IENCXL?!VujZ@4PTVTqAaBR`rK6p{(r}z2gYBd8&E^tCbiaJgzV&H;XecgI(4$xS+xi(E z9(gV9EdT^EQiNVFFsM6}38ZWPMMxMCtv)j%6N@h=X9k&9?=$1{md2pS>FTy!YsU?nO%KacX`WQn z6NxC~I`*#%aFu(p4;&)|6dD;GBFW@loFR1{i)U2fx7iH(vv|?UV{aexnc`dY?%>yd zk(#5W1$F=6&sBpbKYfbohhB$PcMSHL4#`wx)3yiGYik?EiavrG zf2gwBiIsB8@&t`9l%bwaZ>jo4j+4tq#7fp+_ndY)dt{uT*xTZSp0-aFFSJfWmP*GB zNunvTcz6#2dCwnAAgo?^{j2*rH)KT>MQ?L&gEzNw0`lu7BRi4Fu6vV|K=$S3`SAFE zk;#5`rX8-+zdgT41A&0bJ^@T0KF`?@oE`G~@O0*26E&2w1Tj#o+hVdIJbi;z-+1w^ z*(5Rkh(Qs570>WN24cSXCbi*%^c^5U9ddYhmRyN{amH#sf>rd|!{*IIbxDC>0{2l* zmf;r3Q&6YzF}u?Jz?e3H>D+`&x;J9T616Gwti$*bK1Ff*Qa6MyfE<4HoeUE%<(?nO zFKN#yM@?(=bqHukk|mIOR7b6x@dqR|-SUy_Zz;e`(WQW=8e|Dp$fY57{9cirb2xZq zaS%ybWytJGE5I3}7ypur`~t=6naH4A!*Z}mZQVidQa8^FQ7uT*zVGzY3bXUmcgt5k z?oh7D(~?EvyMwW13upvfNs?A>q<@9pD;{s=b5l2=LbnENRDXI$=a z%#S-4xDl|7O>O?w+0_ZtWfY>x7p?~VB1R6sqE0Y(c=-}VZv5`_l)0l6&$f6%G*XCl zmd4>_%uhb$Mb1LDhWIyPF?vJ_XCcxdi0%DS@^=zln#H8VxuzxY@kvJUxwYF#t?n*0 znoWtM=??M`$acxNtQ~8XAy+`fs531YU5wrrNy#E?bH*%`N1Z{D7QC-WxuuVR_Fn@< z;pp&gKD*I@;OF3hLL?MLFJ98kw`!&aqfN;LAljwqk<_esqE`UO0J;Bv$1%wcps^`Q z4v!xJZKvo6Fb^sibR^&dXihe-aYOEbwj&F2|36eOanQI)Tw{QRKN#}hr~BoHD;jGX5LZOksVhDQmdW3dCYOOw6>6eOZ=<+P*4$@ z+BNMZqNVKsKHF|DbJVh>hWIf|82L}N;OtX_Io_6n9oNi!TW*ECY)W(-XAAmtIksD; z*5=@PR$p)S*`ko3%uzF9|&qK@jN{gtFYVAPV;HC zLQsFB?%V6rm_}5g#pC0D1AXBICHqgQtOYN}b?&eq?KO%|ht*w)x=O2Y56u0eTIg7n zdOM?#>-cu<(4SP=cl6XNKE5CyEl>j;J#{CUvLJzHKl$kyx9QE*YnpDJ7_VpKsc$#f zL{pW4bkDR$?f>!iUF3s%HOg*+*9l;qcyB~0`JAiar@5-|pM2dHflSmKLt*SvrO)YU z;XrP=ety!P!l%otda^&wbLU)to>n?6>$JAfGKI98r}V)hGNyx51G?c+JvP1%2~ z3MJ3q4<=aZGq(Mg@ryn0b@By5_cllRcfiG#ED+Qn!1pSc)G79&1rkO#C zNrZ%fGh14hkt7_nWO=EDy0-Yp;2ooj_qU)>5PhHRs(6N+iP0s_wB538iGEJGz%9ii+%&;T>5FEl)R%72MQHBlRVTSCp{nd|ITf-EMfn=jlQ zPCBJi%x?%TO`v`HPtL|9Y}eWvoXHK(t2SCnk#I5M)CHsNCThw*RMsuTq8pZ&&4l>p z8QpwKptQ))kAft}a`@W?JyH^*=w^dQ=KDq6)OYkJtZqAgO~7N%%ZZerXPZG5?m2g0mAOr*i92I4GUEsZgfPlz=fd>5Jo?CwhywI%Gl;ja! z{`-~p)@C6fyh2csm(dR>J}L1JFXuDfPVKZI@A&cQX5*V66u>IaGSaPsY=5!cA0gU<|d?Tj-Q>`$LBlrto}Yo<%O z3m-zH%UY{~9Zn@P4}=dy51ev$MR1cU_A(Xxnv}{}Ky~;e!^r=85bp&ctY;Kvd49qz zH2qLdqMBUZg^zX}`LE3^P4iD`9X`?4Yn)FjXh;6gCb?gfDbKJSS#n`wCY*SR-SP^< zn~{1S3yyU`K_bv#u<2IyLJOP)1qmM{OCQdG)#8RB%HxM&CP-A1nz@@~ZJ7a@8Caz` z|K*~s$GxL+z-_y>6=Ufb-nFYs&M#sE)&GZ1Vr@uSxRu5YMPFNU_@cevv<@B%oZHUr z)~-uNswN__Mh{LM2-T8%V#To6j@Vun(!Yu24p(1F`?0ALFEvopd%iomWn1};9;Ltz zk1qa98tEaeJD9urVJjHyE{)M205XYc>(0c90y|2eNr`&aALQp}};ZxRnl6xgVfXv3szLnQn3J$G!tp$LaD=f0H~ zc7244{m{`_JWGtX#>llMv;DcVPv<50dChq^xjuErSXfgzC5zJB zlf`GPf*2n=?e|So;ol8qebO~Dd}3^j&;PJ9%AZ{0S&a^+;NVdQ1k0f{*ZNR}K!)T5 z|9CW*1=XOqF9{7~dDz*T(ZoOarHKhia$dvg^Pd&2Z5%L96GKk=TmSR3On<@&e29Sy*;8e(A? z(qb%#Ldy|PPlwQF8@`$4<7Y`?kL|VcGg}t++-8I5t><8CY5&(Aw@-$94>_h=&j;%? zMVWNB&WaqY6W17om2$U9;pYn}%iqwcHNgb%rRkyYsZNjR4CE}eXg;g8UurIu_qZ05 z336<&wk|f8+ZbasFUV-aP3?27p1dWaZeyZ!gLE#)fRV;nosz|?lC9-d4E@i1_6M1= z(r#J>9}cx0qvUVnHJO>Be0|15*opma7VYv0^MbP8!Rq#28Lsl!f7$J=7s`*DRw#>p zZ@6b`JZ{MSv4FO1J@U`?r_Mf&CE%N`RjEI%QCZGO-K})keZ>(gA(`b+iy?c*7**AR zz=WG8ym_T_YS8cQPNMXP#ol|u!3|R0r5p~gx?c2f&M597GnBE(!f33dH(^29&Pv^V zZJMX4+UPcG<+QHJ!XEk2VNhX?&!G@iE;GFAwq$Ou41{GH^45eK&9&>%HE~PlQRxQ+ zZs?w&Up`WEmCWO7x%TTbiu*T_-hx3d%WI(k>+aj@6nI;kp|%JuskRA{beCSqofPD5 zgA7z zdnfxz6jRz9MbP)O$QP079v&C$5fk?NqO3nmSmL_Fm3X+ahq$R2kzMHf2NR4DM~S~e z9h|*H{hlSH9gx4aql35BtsDefQQnnBU$&1W*{pqn7x9dEx{&%pB(JVLv(qvStg*b7taw$3 z+Lxzj*b^=?W-JAhDgi3x8(o8-pbPH2#lS>>W!%e_8Gi1ZwV@HFr}U9bj@R@7w(Qr$4_ zgOqbS7yUtAMyQ|EciLs-1SWnxd!C5$@JD~J(refXF3Y8*PZJ7Kv#p2Jx-$F}7gQLE9 z1&33)!f?cKWz?{}#qiTJsWmuxtPw(+|d;rlcV)$Xo@b1s4#tveJye_o#>j)`li)w!&|g zVpSzlWX<}SpH^CqY9^ePHgKB55a>?T&+e&i_B0ci8qj>*Cw%NiWk@Or>1<3+JDv*g z_D{Uov@oLT4zbY4c``NB9; zB`h>KBRDyHv5BYhadXSq*BY5Zzez^0b7>Zv>hN>q6Y>eN68%)NYe=00Zw8WE9J{HD zbRmf?e>??ZDXZQ2>^=8d3$spderW%T#sGgcSG68@4)jJUmS*jB32Zzb&SzOz@_D1b zLjWE!l4?`m5-Ev9N*sw)gu0aYKETB!<*K4nI^b{qWnzHsp$7{(-Hn2iF)(^OA#8Ft z9xY$R|4HiRC6l4LlCSrbl)1}ka+8|yH4?$8Rk*s$FX#wleZ)nMk-fj$FJOd6euKzrx^S?GG6aE} z)Rc`Q-5E(7uO!S&*fraTyi=ShExTmWmY@6iEc)N-I0GcA#vhM`J=6HYsH8`9bB&{# zb#@SUOtR-k{$PeI%6sYHTe0%A4&de=_WIw^BL}&V>v| z_Ntea?tj;2lZR01#0G3I8t)p@>Q=gq7xgf7FaON$x(@B)o2Ln;wm-e*kPi?~P zKqHyTM%fat!t!zB&0C|=9USYvYKN5Qaf1~%Cd&7(gVPc|OZ2GBk<5wl5=X6b5%1}K zmG*+%q#3H#C;Jcv&JDXar-UBlbW_Q-rI0(i_cR>I56hc@bMwBFktLA7YkhmnqH%lY z(wl=qofg44h_ekOo-f4YrD-;8r zb|Zq0j}v$;%igNEuZTHG&6V)DEzg(zduxXXfipttRiN9O(qPOMclWL3Tr=q&`c*xT z!EZ&dZyq%|qkWkyDnFf+V~OFtj)kAr`B=wNjXgI65)E)h5ueX9zZ{(6Ua|4Vf2qgM z@zl-K@%nIk+2<`@%qxpxoF4ZI8L@k0kB#8YjSMQeRJ1uXi2r!AGM`N3KsEQNu7F%s z1hexrb@bkMvRV}q8~ZD*Q8 z^Kn>1&sS2~u#+pB4pixv;)ezNYS&R8m_BYczuQI7mU$v z&@q{eQ9%T=KdPPh^aGD8v!t-0f7i3-KR(L)9tUrb>a;0z63~xnx_y~=ba*qcM%5-( z9K(y*+GhY_D2lfHyrQre&uWqn#GtMmEQ7=xj^{*a6{@%ug+ zeA|3brC*tMXbeKe-ZcoXn3d@yqE}WN%Oib_Cnuz+hXsS{J5*9N+>uTJ!tMg47dr2oZeRNnP%WzUZ-Dn!gYvyLzs46|w}2dZx?S9 ztHMyX5nrG$5=!bHrvgVEmn&ZK#!=s%kwL^64O3`cH;iU|D>4mbQM^jSf5%PP*O@yx zM?RG1+Vgame21KP}8m zLsu7R!9DdpZDvnP;++{`9mz{(rz}do6s3Eii&Uqb^y75qaV>p;pC*lEyx2{s##=0c zs$Q6#L&0<-3`wi6Wc>pBl-Xt2b6(Djrw;X5f7>hvo! zX;j_6c#kjhRb|~fT7L_-wjC#|ojld{1NU&9>ZN;A6VX$0a}368=dK!EmhiQG?w3PSKcBDhtzD*!Kum4#cAD5`K83FI?_TJRV$r$y8j{H~k3ddC{ywN8Q zH0m^M<0JQq>C$J(>WsKYw=EvjS~6?x<#KgO5ZDAA4G@7s{sE>mx^1whf9gsDwPKO* zhNN86NR5n4tb6EJuf$dy$-jJ%#kSddeS6?Cfg~Cv%l8Nkrm0c&`jBmmt+bT*EEnr& zsY(L#O1y(LK|NnC3qJPLP&@#K^GZH{&_tP?6ntAV05~MUMj3~I6MByn|B~TXbhaUK zvv9;>;qj2u_judC;dA}*PEa(Tl0#wr1m44QUQJ3Xsh3W>mLQiPIQg%&9=(tI_5Ir5 z5wIonph?i9K?GN#1*N0fSSb7pFi+AzyojpFTct-IECTns7lrCE@-(U3vjV>!Bs@^O zO7hnRGbxvqp8q}?zM#_#C3@UZsZ*O7b!6L~A&rszy9~!+8)76k0e|pBjU4k{@IC)Y z9Gb#_Uf5h;Qt=oK;#Fb7jbGcnBhTVMGB84bqRZ1R`BsE$gKGwg$AQ#t-<$3<23_x* zw{S5Lm<8ps>KUj9gLe-3)4g{YdwfjMz`;7aUYwecd48k2UKf>3TU<~JpiU#vdES-#ZSNT2C|?GwNx=XXaF z&jU8TiNARZ?T0LtVf3nDm9i7Bh~frI4965TMF2n|T#{^URK&XcmKdrt8un~+>tQ%+ zb%P>ehLvn6UuxQk^?cuO+)>DaF_3^*LM6}vahdK_+P;Ht=_gCncHy)Au+p|DNYwb; zGTW;S{yN}$@Y)=?=h&o zq|NkWO`1R8{KN~n?GaIJOF7fAPy)YU89rH3&Yv5SIeXf0gC7!E&5!BjE9ZmNFxqmDR`ESVA@e0* z7nRV<`)4eneqTuF&XNzcliG91n%$i81sa=t9uU@*HW1h`$%Z?ktrbtPU3SgGK^yCg z-ycs;X1xNo&5T-kF9aP}P|#Dy3ok01#-F&7f)DNA|LnQQ5IM;*MtD5!RwnSP?x1~Z z!M+LSNPOENO__>3-BXF9(;EYtQHTNucp3aNSSQ@J)Hr}&EM{$s42<8b82r~enQ^C@ z>=LZpr9WjqcfP6B)!crhqACrL+E}r54=BX6Pt9viC0a{)AGfPaky@BlK$DkA30Uok z?;lH*`e3{({`t<(gM^rRZ2H0KryifMu_|LXv?*XeoUN3HAi)LYn z88@#i?-Qv*NR4OlyvaB#Fn10K5!Hm`W(PYMp<$~mcXtcz=UrI!>L#dMaG>joDwf_Q z0D)?bpxE6zushnyAYSbqu4K?L9_Ree?m2$RxvLvBv5!5C%NXIte>LMm1M9KK3^Ek~ z#W|sR{`;E(Wc%$7il0`I!b8S;adN;<>)lP6)P-oj38CnWdH3^?ZqOWlvG7vSKK^1( zO06DL?oaArDUk^JII7RSs{1n(GZ4TtTVVhieUgkppw)Y(w-D zxV%q9Pi+rt;w`??-m``BPZu<3Kn;T>;&O~Mif?UH62DN8=|Q_G>$32jq`E4 z`uJv3+ZqUT^quC|b4m{V-~C3POxDEG0H^hb-dx$Jo@#^b3Dz=U-;H-aGmpG}O_;19 z-s$2$FkP0tDy-@bEZ~9&oU(4pCP_mf4;ZoSK<3tEa8rC_=;ZWD8(r9KzCNDeyLi9o zAK)Umid_C`+{8Vlo2ifum$(|`A~8yNpNg37iHKvE#>?CD1u6)J%(z&xeu8LCJI>o6 zi#F!f)mQl=FNy=XIQfatYCZifXkWL%V(gKBk;Udm?7nx=V)xz=pc(dJ=SVv`6{hD8 zyYvm|M4OY^`04h1e!)(umKdkz7+Dpz247IOBgw25-dx_bSv&Ddg*gWGr)3he$#b{8 zyP=6*Y}wKBt{q_JP7ZrYN5<=AD``+CMyYx;wPG{( zAekMb1NI}+6jZb8`i{iHdOT5hJIUW-|L|v;lRd6%oksfe&alC(?{bWrio!*=-YnfW z!aRkqE~^?WoN;}U)pXW|k&}G3XTn0vi*q{-1?P#$lQL*v^yhy`2?kztB-X+X_v9+) zI1ayahu(&d``k|Cv@zj~%GggRy$6WP6Amv8|+;Ot`VjciaJ!>Qffq@8Qn+5 z4RyZ<@#5tRg8wbo=N`I)h_Vz1mPlo%S$>lUGESN6Cj<`6vyC@kFzZ}?iPp(Ezb>-l zbe5Idfyu?@qZ5-3e3{7@T{>0nYaUJyJD)Ti612Ad8FrfyH)KamVqI#vD(U7P>-#OU z|BV9o?NS=_aB%s%j~^(k;wW}2`IuGrm__*aZzccZf2 z+(MKF(4mbV!9OZb`{G&a3agU!`fz1eEIJj^*F+F@FXFmzv*`p(Ne13u4xjbAk6q7yM4btnb>>>b#k=OAbDD? zC5aPNS+JLy03#O#pdik!;1WalI5Ml2&z}w_@h1n{ki-yiFeS)tO5)_T+zwwn;Ajed z`3jrw#@(Wq@Y(dP319)raZK$0sR`BP<(l(}8G7F!P_~rbbqiQbJa<~Zt6W+^b;Xe( zSQ$4|9S3-e!T=LFNQriO@6<_zk}yvU=)*ov27m2F%|N8{S9;exU^cJfC9x4rb&XRE zP_U;16fmHDx0I996`q`H0;m@$FW~b)qCmXUyal!2a0gqz9>ZQT`2`ud2!LTsiJ~3! z$=%p10K)QsHqo3XOGkyh3s(@q*O(!S28@Wfp?dt#2-ZEfX#$ZDiEq2)2ACH83UWK@ zb@-tJuF?45ASD*znRF3;HhDUp^3LP(xLw6#CwfO^Ge$P~GRuFgr_yNXsdnKUzbFX( zM=&k}`(yvp`284@5Sw;4I&U=YywKscnWIc z(+)Ns=h8(;Dw^{J2dUk2-O8*59;pdyWv>WAg9ett8KZ{oH<}3r7IHiK2~tqo(l<*g zkM)Miz{ko~0($|5@Ot+U)8me^0}~=KX6T72P4>T*0IEEK_go7K}B7d zJ<5R;A-ns_U@z%s(|f5IOJ$Va2MkvjmN@SBXJ`1N#ZRxE4nFO+!8NKaJZ=TrmsQ!% z%Du9t__P7MLHo+at@@c%4o2ujj?NkOO;m7z%$H_IUoh?=a#=pQo>Fy4Jz&2#ySw$OWTP~Msc@+^0`-82mhb?9 zyB}}!nJDCoUYKU5qUI>^n^2_FV9Ky3Yyp94Kh6?@P<3zikZb>p{XeK#+jDsb_UiR5 z)(nq-ejk4S8dQ^Capd>yh#hCyS|`K{5!g@vR*Ny*7wpL9n~(&CObV?K|KTbY#*_-D zAtsS8Wycu!(Kt&td&0_0o=KZ69j3lo%^VGyImid82?{a4DE<(fQylDv`2;B!+l^!U zKHA=>3dYI4YqpRoDNbyby%L>MEQtQtOB!5=u?_Yj`R&=p`*5u*mnso<{RM@JF{+7x zBF(P03!MU!L0ANmmtVTj2n1xjUOSUVHH#i0T*KSyVf@*6m(cGL< za+slGZ6_03_ewn3AvL3=vnixY&Wze?f=%mUN>Rk5$ZW#Z6u<9zvzD$X_p7%Q(psFt z&#jGE-qNh@HP&^CEbsnmjiF_8PwIeE$+Mgpj5x-K5O~Jnv<{dp!gi>rZTs8Y>7V^j z&#M?XVKE{Sq7f-Xh!nsp#1W~c_&%XauP%i0Z5g`$b5C*Q!8mhGqGj2hv10EYur2LC z-Hvv*EEP+jIQdPRJlWX7pqjx&Qt{892|I87yJt^f_ht@Mkg(;{4&-{_R;UeT3m@&+ za+RY?!U-;y8vYdJ+S*C!?Tv>=fIV2sLV}{7@WUy8V$KpnYPs~Ol@YqV%eNaqfi9x$ zCUtP}fqlguhJR?oVsYquc_m*7hmkUAD)N>Y076E&-5RSky|YY{9|byn0G@cVaUVb& zAV^t(l<#`hDJQ)o`sGn<7lkHaKxvdtbak$y$XmZtGO}^|tR+@9o^VS55Xaz{_`I|D zw9!~+{lOqA^yB~T0$`i3cxh*vYq*S=@qLoc zCRN$q)9(uITLB?-JvayYoDcf3mgI8`zEUT*m#XEjAS9^_RK0o!?;dK~O3B#3xknox zNLU2Dc94g#$vr^RK_d8X5S$iByWT0fj}RwcGFA7*^}YlKb}0Raos zEcMJCRIkqw;hamWRn>X8_0DfyWO_^Q4QO~jOHsniZ>pst2zIwwQ0UWaCo1%>8%@EH)OXM5b(EgihO*Q zJ`w+JyR!ACBMK70&!|&i&W#RnG3RqAId5~TRpzyGvl08taFslEK~^z#`uQhezcK3odCYE)ltjQGG|Z=mSI5Z|z3!-+{2I$QKhwV77Kf z$`r%Roa%MKtwL-D)}Q++pYPdR#Ssv(qMZ6n0Ww$CqZ{8|OMS{`{i}ujV6b|E?}q6aGxH+NRDIZ`a$3PlZmC+BH+WUwEFb<;wcIfmtD|PcIs%D%<5p z?bF}t;6)Jfyn6V-!o`0qg_`@wW?!W1gs{L3TJIL|P?|Y_B0TK4X8rDE?y-tJ_9K4I zTs^?0hMM)++o84EP6oms=N??=7ol>^YIE~OS7)gHW}qykk+8SG#$$n|wj>*IrE%Qk zGZ6(vACR^{Mh;>Q#U!biRWWCH9A%)7ay=6QAi-_10+rmx=zdP3JY@k_Dy~vAVY75I zk5n3TyOQpH6Uv1umv`u{E974dmOs!UHM-Fw7e2jGOfI@Os8^L{g{4^*xyH)(|@SM zV~yf55zCHi6Ch&Q^mu@|V@Xhn!-Sq*mo zdm52EzkSEc`j7*CH1>R^@SKu2_LsV`-&w+m)3hkNIR$eiUNS+#-s`t=t~jb#eTKLJ zna4rnH6dqKin+cn;|{`~J9u)f*s%Al$m2GoU}35NBd-+IqbXX>YcbRubD2<4*q0c_ zHx1+B+Wd8lMF-rq@n%=~Dt~i~S+X!z8uGITdcU_u@4gn5Tm$icvQ)0H+Sj;@$B>CV zbP+m^B)T5YYmoN-65{5X>yj_>hPn4prVTF>V);}3FBxEp{jj1j6_c7lb;x=kONYw0 zr}B^!L-*8xL$jXM!ku< zR3Iy%uG4IU_%Eq0Fz*Uf*B{N^v6#dj84;scUiR%-EYawI@3TV}>P3gY#bvdRBo6#> zev`{c5Vt79LvBp*%HqFj=qTh1I}HpM)hmJHcYZU_t?D|f?%(5;_I`^VmaOkw2bHmn z!ldptIY6E@ImgQNS0~h7_!1G*6cCA)M@~ zr4$x3YB8V|`(S5ygq|%$~v+Vbpwt&eJI)Pb>j=IPHRq=|~ zAth!*@|(l|*J%!;cW>Qd!T* za6&@N_eM*(nQ_Gc7Sf7jiSXoc{xnkugeJkGo2PSk3>7GjNV8z+8#YU9t!zCYYl@!T zfu(@+0LJe%48@`s@&0NelAJRzB!T4Skt}i#>553dCN04 zVY58969%)J-wzyxSs+5d?Tx|e7Q1ig~{G zJRn{9GqViaSpG~wSqSm1uTmBYy}$lv|GFD}MzLBoD4Rr0D;Od-U(tyW9#U;wBxKK|^2W_3i z$B~=Cs+r86%&1KM;eKA+K%aZaN@N-xe0+?x^R)d9Vu=iOP1H1Tr42_Xu08;}jkH8Y zW-xjLqq7hqn3`%Sc1;sU&IDd%9j)YOrJ|(IO-C1JYiV_|W-dAD%$~sE&jZvW%e;S( z6*EbQi=@}FN0KS8V*hDQU8LKEC?JYRviF@41VjNzLXt^{WBNF5ol0?7hGZ?p{_rps z3vN&NHS8;6&0K)|EDi^8eXoaICs;Q>{1#)2+r!>c-am}Pi6A0L0FsP!-QQ4_8JNR# z_j0U~k~5?xv3>!|riW%#)J*Ko9!kzeWF`aLS8wlh1$Dh7vHK)z=bLibU3!rXJ85-# zmo0K|f4cs^u%nB&cCqyckFRECVX!S~w)6^S01wE*$pErUc~!8tGNZsmp(VI z?cf)GqqPG`3d_DIBg?cp`H#Qz>h=Khn*lU?vrkF+q0Q=l_I0B>I7l)-{wo*iLr_{2dErqCvH=<${NpPDuD6Jc8_EBA$nUC5 zn>V|oi%2HKJ-t-c@yCzYxEG*!9CyqKu>(Us(MDj)LC%MwG_ZcYSLq<}NSv?dy#szP z&_?W@UMyOyezum-(gCn|YG^l}ufx%)!E!(+>Y91~pm!M^B%`vpYXN<39GxNDCChwp z*zfe#Se`zz%*88YrjU~!+KsP%3}Cg86z_FW9g#+Q5^2d~r;(OKT2d_6;v04nk_(3@ z@XQ*l7B=l;&ZNN8Y}LIRcJTZoK7OQ)*zs|pJ+?z&5dr$bGQ+t&I6853Qq`dTkJPCo?jgc%7}Sm35r04egdSa~U_1+9tM^FlSO|_j)AGU8dp^Qwr2S(njo* zL~Vvpi^%v~fGe$9RCgVHZWtxfuhX3$?! zGqL9v@#ZH%UD@2ur>FSzls4^Vr7|wp?@w)3@8~*s-QMM*(LtNj`vf#yeHxnEwRDvX zeu!Ezi^=))^z!H6{)_?X?xmw!VOZ2m>_j_rCs9&~Cj#e%P_YQCoEhcM993L)= zZV%3$>z;tCPecEspc7fCJh%j4(`U3gHLJFvO&_s=^$P;~5^0Og#>$x**J-tooTVLb zo`H|TU^=>Jb$Vxo{nNvi4z9EYYqam5!;c%u@4n;vg6uSY{|^9%&+xksf~r$M{RnDo zE`4}8C(a{Dx|^vjA|ukc{T7{@37V8dQW6=X91O~;`1z(7bqHkC9%>qkotDH?xATV& zwXM|`0$*F_wXGVK;76TbZT9=47an75PEcE%0Xv}mUu(f+md^;y0U=Zbczl)mH8LQX zDKYMV%5g=PSL3nO6c_6C+6e;d7qF~Ym&&yzJsDf<4y;%$>ZeT?K}3OXtf#mzqT>rb z5n$aszOY#1YIQ<@F(YHvdO@~&eAVltXS4FnyIDO8&_?q9cpHzc=KdvS@)DmuHZ~Ir zi^%k`>O$SaY#goRPuu8qM;c}$Bbjg9#kknLDB)4t%!{wbrs@8f-Sz11sWN9GMftqD zm%U|ygCq^cA|k-;bNIroraZ7YI*UugvQh_~_8b$*wo1{E7vuC$R!5}%dFs4H5Kn#g~>2SL=%|!W1i`yAR5W_1%Zw|w086GRN*Wy@d#D+W z*%Nqp1vXL3(AxdB#c$oqoQZ+1)T~V%STbEbsrl5*(=@=<$Ij!(5Fe+_e9dAZJ&ETZ z2`bozp~X&1QvVLeDot=;a|qtrMME2I4_!T^B!UqBfk;tAfJKve@rhuA{~20rP;X_r zJscQ(aKj`VKgZs(YyaEkB+<_JQ9x++L5l@oLLSdQ!qaO=um`%~D#kj+Ihf*cWTn#F zey!xwQ`|nsOdDVQbaeCj4t3!jw{Z7DF4VK9ltZ86>hq>h@G%V)un2f0>^9~VvAj5( zFfv9LTM$?>O>w}yzLm;aCJj05G$0#x(B7pe88^}!!L2Zt!dxC(#rexr)KJq%T{G?7 z^!5S7SxHG`R2Bszm|VbwyzsXPj4n2?w3sai6^{FRN=+vAo>KK854(-$)+**`RtrV> z6y@vK4WoavfsACeRs6_Vx`K;}X9SwsdHYj!;X}(AsnOBb;4y*N44S6(xj9e~qppOA zEc41%wg2|?vEGPpQN|o%&nzTeX$92ksF>b-c$hQFunWlvJhLV?6HIf6Es89jt|+N( z;zGTjs|`bS1Dg-33m;z{T8tD8F^AZ|vSRfXg27*Iw}+RvsZVh(p61=lj|rv`dqgTz zl|e!dpNaUyx}LndPaS$OBbi55#HcrbiNpq$DJM0qzR*IiM3b|%e0)q%A_zQtr#c8n zlrfXov&VbG>kP2RkRy4wi$8p%-i=)|$4B_0C}SqEtrm6U!>R_VeFeCQEpL3{jng>5 zs7$_aYm9nx9cB`n{%M-B#Av>0$0|9fv;kNxJh#peSz}Em_Q(t-DGiDTD!f^8j6ho_ zuYIg8{KBoF#hcX+lZnkB-?W}yj+}{6SCq)`+IF1Eh-?!_sRQW85c7#WcM{3U(BcLe z$#QfSU^0pZD z#y_SM8`N8bT`mnmK!!(E10Nhx7k>E;QWJe$9aGFI_WUBX=`kkOv|cxV_)vZ5eEAG! zjgLWR0%BINZB`acR+OBn<#J23yYbgO)GOoQk4WXAWzp_NkeF3$V8x(7mQkLjl~=P{ z8GTX^c;?Qi23-sZ6N{ZcLLFjdUwK41enXHvWQEELr%q{l9De5sZI)}jyRB%{nqqSOic8$>kznEKWyN&rpijsb=!$E8Y?Tg5=#?!QOm-*<3qNG0!S8}|Tt?11#5qsh&MrA2V_Lgdvp3Bw8%Ujj8 zt(s-Nh>OESY+$LyIl+C3+o2bOA6c{CY5V&6JV?XIhdZ`z6T>UuiIIjo-_QJpblScyHkK+6c2d&?*}t0;-H@|@w5i4B2iJMIf%(97M_&gn~jt{#%6 zcHZ8tE_`S?xls>U(ajIuRNKJ6zMgqSerhle!%*yo zHh%dYms_!jp=EBjhzJ7XMp9X)C|@*%udLO!kFjA`4dar`hlkmG5M+=;QyRRx;OFZ} zup>gJ3m_wzM^|az)tE4R#CCM@+xIzFj})2bf+Tqp%4em~(jNOjC>k)47u(s*Pu`)+rHkL0 zN22-)zu98$L^K1Kdp0h^FE&w8Gt^uxEs3IhCg(FIo3tcS6Y2BN+)l+McAex(tKS<3 z5CraBWb^|7!C-E&cOK`h-2q;^A3sNWvhN>xBsT74`_aG+3Gn?dnRT;k025Ep+Pm1a zFW3S0OfCD%`Mic!C-HGiAIk$v$V}nk<#f9gsXKfkh`jnS|NOXt0;Gh2iN)T0fW9EU z)0LOmR-%ZE;OypL1)taO&ySOmz=O-!e>%V?Uy`V6=3oW4P95qpgJaeSnxm6FWkH!u ze*3=fVAX9-cAWr7jt?%mip-XS=ANmURqVZG_{xzJ8Uu&-{e9H0M}~$rbEgb6vDlH@ zPX>a#yMha4Z4u3#{MD3VUumVu5&4Vl-N=&VV3QJfBu<>ypxszuO0g?yG?*37FY?CM zDmfcM%EvC3I%K?wFs0a+8X`S4nUl^Fw*hp!cxO;#!XXd^BL=+=5>tv@(;Sg;G%23{ zb}xx`Wcbte&`yPkqB=a1i7=(utsQ}{@rT{UckUxM6X5OLA&1J7q=;INEv6JZ>;U67 zE8n`;YxR8ZfI5vwFi5gGBb$jZrP$#ux-25!xXYWUV`~YU4+Ofw4}H;!zNI;)6gw{T zb5^3jSJ!z{ukSp;JA1-xTEN7PE2b1XDa2FJ0zAFOdtiT0DQ^vmbrd|JCFItPgDJ(% z%M5Ml_4sP<2FCu=yuKqMtB8QH;>CxADa9V0g(YaQzqrhMlH2*gOk655Em#^PNdQ#wPO~h~zyS|0L?+1`1dL+`4 z=;%Ta!ZEQ~L~IrwTF$a!bEN$U3DXbblEll~6p^ePoy;p@Suqw1q8OBB{WI-28=0x} z^f7wGFjSgh@MeE>M17tkJ(lW6CGC6rWBa+WhS^tutia@}5;EPG%5_tT89wIEqDcM-^8IJjTRBr9w%fzLa@LyM z5FSvsDS z1Rp6zG|vPVTg)eRb;F>1Y68!!(I6eqN@eVLS&mXR?x>@@CMtXcibl`nTkH^)Le(`#hRB=-5sY%5WeXf=Qj zuz0F^K0lnMX{Hgo&&{jb)!SKj&SlbQEnA6?W5Hxa$(dRc2T@UB8nNHqM_r4eBsY_L z7ir(n%311?-8y9BjtS-v``l%A9#@ozBG0Z-C*RbB{1NJ1ko~9CX`f7r3B>Mo`^ad# zZk~=Yf>kefPcMfm^lB@bm_Y1z_NX%&kILk(1v<7kZ<2b;Yv&0an~NGo7rWw;H=OJM zqR2CM>N0>2V70JhnxdqxS)KpMj2K#MS0Ar^tPYfL*MevyX<0c_?YlS()?kJf`|VF@ zbSO#+vZIvII4f1Xtx|H9j;?4ltslk}`}8G6&Q!o^;n_Q*cMM-OO>=t!Cmb+11{J&8 z#htw`E$}z>DV*lk+T9i>E$K-Hlbp3<`fn_rkB`qBa z?>t3Rf3$8{vHGjA+sxB6!-?JHV#5w~;eCtMn~%{UCBYjiZ-7%5 zX)>)xgW<$}^AlQ~ijwhpu{;~?!=u5prgCG6ed0U^l!i&0l`r2B%WPT`N2zCpdrH;* z%VxnqVmo_yeb4~@z!FAf#-caZu|oNBJG(=UQf?3oB=#FSadaw5Cgibtc8q#+9k&h_ zj|QWNee4`Z&L~RatUP|jR6 zQ$vWoVW-;cJf*;g$4CqrmB|EUu#E#I^k|5^*as^pIjbnK+j#1By<*~ojcN_%>f_+) z7^DB4vqw=fbqq_3{ahVW ztQM9|SCrJXP+1$J-h@Rg#r~{Z?Sh|R=jl5PH-HbY!sH$eF%!G3lfUd%7k+64nJKa8 zO>ktUs89MIt)$&N9t|-Q`_=7qxfCTc3t2qP&((%OHBEDS*lV6OSZu`JQ>xw=PPBV7 zp&FdxLiOr@_bJnOG{ivc=63%2sk-p7Rb-eUz_WllMng*nr!K^(Hz5*jv1NFDhuR!5 zYrNVXX=Ij8S35GBWttXkv3H$N$0|uq;7KzK-~%KlFn6M&r0k;l7=tm1$k)E5gU@TI zZKAG)Hm5iFt=&dOGI^Pd9>L^%#q7GNop<-CD|vhsX=V!%x^k9c-(7}1rIE(@hyvk= z-R9)8a`u(e(1s`?qE4xHsfqGxBpFF!WIBtdvv?Y5iM+B+osamI38u`aGa-*LIf{+1 zy`|i{NZ)fRkrP^k!{&Cj9AbYt5NsG&0dJ0;;zCYcP^554N#vy`NikCO0QSc3g#dnDdJ#0#&ozZ{PgLcm`c@Aah@5Cuh0=OkAqp&zi+w{1!Oqb^I(Cg+u{>Hh>n$;N-@-o#C zT@F^z?ecTA0T@c`+Gc+KE^bMCbD$*A>){uh)L~Lg$6$|!{RWQF;CD9O-OG!w<8a~$ zr1Zp5teVBdQKTl)*+X>$d&+_eA0`T9rt&Y36K~oi#U6?0|47?)PO*8Jy!4bocWM2K z{kso1dJa#Z_Nv64- zRwu4r+#cfNNQx&rJ(lUWeT!XI#m_edzIo|%zI+G3>1y8D%jFg_Q&>OWyHmOSC~pti z@bJlZA7pAl2%R<*EggLSd96x-9&x2g@(tKNHU_xoC&O(PeFE+`srhWR&ti6w!m@p7fkjhlisvX{RnUR3|U4L z)bkggND^0CId(4C9vclwCNC4amChcoJ4V3RwjK#t#^d4WIsWYpeziGDv95iHy|sj3 zCK$8F19Z74uU7x4x!s$QM-{=_AA+EcDs2`T+W5hr*;axptjuv94>Fv($P2Hs^SJK5 zs%o(t+Niz~RCkHq0tU`v9 z7x?izYTs%NQ43pM6_l|o`Re=XFIrT4xBAMV@kl;C2Zm*D8E@=FM&p53lBj9oryKQp zzZGK3{ljt)w+)2&?(;Jl891&UA7n6ane!&Go|azZwe5O+Up*dboB8z?T@p_(`z)PKxOku9~pK&9-@5b*wYDJRy`+jB?YPbj8I65zFu`Nv1K zG_xzj_V)oEOlJ=r-J~S=J#IPTYI#5l+V%Xu_eivpoIadh2bhmVg$I@(2uN~Nk4p5pakz(i6s~<2lmkOn zYT#s1j!r77V{r7|B66TYGmmtI*l9`FZNaYSdwSWpmoMMJ*c`rdpJI!%KU>m{W1)Sp zt)klhTtoWYG&=m+`-Yk*q#%l%z7%-5r3W5~6X*328yKHQ#id|Z&wItM(O1i z1@f|(sh#N{NURpplSohU{U~(zdLM#TCyi}vJ{axpT|+xlkq<`&0iIZ`%NCnYWSJ*c z8_v->A&$IErWA1NRMzX69WWTQ@~ijll~RgdnkJT@e#8BG_Pz6 zVIK3f^~@hKe8};0{AzPhRpn*!uTKTr?$88yT*u__{YOZS*Ydfxh@>R){V$nDX<*uz z7#PL@i>T!mXHYR!+PnDO2b`^qbTK9X0#ge3>N@iU*!by2&eX&pnBj|0Xtu=})C-%M z$p3hdM^<3Bh5w3MMC>*mUCDpH-+W2~D`!SqX;EZMj%G>|d}u5|VD)U~74gv#cAdl{ z1^X2jKoGHrtenZZd47G?jL)2jWT(^A7QNwImbiD3mKBB;8mk{?4~Ht)SI(tIkg-_2 zC)EZJ1w;{#2LuYTSu%|UQ?%Kni!CK*`R)5r5?d4)lcTZ2VK`zB;OyaS4K+>Fx6;;0 zR}Vm9Jn2c~W|E&pQ9eoL*Z6vVwvjWn(b(=31petUjpwitiG2go(!q-x=;_thoGc35 zd#m<`1Y)24$6REl@U?aNF2gJ$Q^&A=zV|;-=W) zu&kKJR(s6`8e$R2&*r-i>b383^P3$$M=SZ`Ry+}e_`DtgW>4g~wV@r=2(5{mVn;$l z8~^z}wM`M(TPz}iz(dP)Pbqv;>`0MhcAsR^K3t)17g^x3O2Np{JUutMeECJ`!A-HXM22&9oH$Qe6?M(NzvU?jOetX6 zSYrgeyNM=95>4&2bl~cv&*OD@9+|Ge5yP;#DfSJ-&2{z-#7(hpAa06%1M&X>S?30w T@&4e-00000NkvXXu0mjf0+QGo diff --git a/test/visual/mpl/graph/references/state_city.png b/test/visual/mpl/graph/references/state_city.png index 990c433c9162c5920d3b26fd36cfdf1fde20d74d..a9af6d8b87f260de8510bdc08706a7eae01e8388 100644 GIT binary patch literal 108666 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%0DgS7BW=#Lf(cg>`CeU3KwYX1&evbD+8Pw)w^^ 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 diff --git a/test/visual/mpl/graph/test_graph_matplotlib_drawer.py b/test/visual/mpl/graph/test_graph_matplotlib_drawer.py index 20fae107d30d..7100602f72a5 100644 --- a/test/visual/mpl/graph/test_graph_matplotlib_drawer.py +++ b/test/visual/mpl/graph/test_graph_matplotlib_drawer.py @@ -113,7 +113,7 @@ def test_plot_bloch_multivector(self): FAILURE_DIFF_DIR, FAILURE_PREFIX, ) - self.assertGreaterEqual(ratio, 0.99) + self.assertGreaterEqual(ratio, 0.99, msg=fname) def test_plot_state_hinton(self): """test plot_state_hinton""" @@ -437,7 +437,7 @@ def test_plot_7_qubit_gate_map(self): FAILURE_DIFF_DIR, FAILURE_PREFIX, ) - self.assertGreaterEqual(ratio, 0.99) + self.assertGreaterEqual(ratio, 0.99, msg=fname) def test_plot_16_qubit_gate_map(self): """Test plot_gate_map using 16 qubit backend""" @@ -455,7 +455,7 @@ def test_plot_16_qubit_gate_map(self): FAILURE_DIFF_DIR, FAILURE_PREFIX, ) - self.assertGreaterEqual(ratio, 0.99) + self.assertGreaterEqual(ratio, 0.99, msg=fname) def test_plot_27_qubit_gate_map(self): """Test plot_gate_map using 27 qubit backend""" @@ -527,7 +527,7 @@ def test_qubit_size(self): FAILURE_DIFF_DIR, FAILURE_PREFIX, ) - self.assertGreaterEqual(ratio, 0.99) + self.assertGreaterEqual(ratio, 0.99, msg=fname) def test_qubit_color(self): """Test qubit_color parameter of plot_gate_map""" @@ -545,7 +545,7 @@ def test_qubit_color(self): FAILURE_DIFF_DIR, FAILURE_PREFIX, ) - self.assertGreaterEqual(ratio, 0.99) + self.assertGreaterEqual(ratio, 0.99, msg=fname) def test_qubit_labels(self): """Test qubit_labels parameter of plot_gate_map""" @@ -658,7 +658,7 @@ def test_plot_bloch_multivector_figsize_improvements(self): FAILURE_DIFF_DIR, FAILURE_PREFIX, ) - self.assertGreaterEqual(ratio, 0.99) + self.assertGreaterEqual(ratio, 0.99, msg=fname) if __name__ == "__main__": From 86c63eb3d719a129dbcb92c56e9a67954030b803 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Thu, 5 Sep 2024 12:51:06 +0100 Subject: [PATCH 49/85] Fix `Interner::with_capacity` for default keys (#13092) The new method did not account for allocating the default key, causing code that then tried to use it to panic. --- crates/circuit/src/interner.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/crates/circuit/src/interner.rs b/crates/circuit/src/interner.rs index a8ac269b1a18..a72efb037afb 100644 --- a/crates/circuit/src/interner.rs +++ b/crates/circuit/src/interner.rs @@ -105,9 +105,7 @@ where /// `Interner::get_default` to reliably work correctly without a hash lookup (though ideally /// we'd just use specialisation to do that). pub fn new() -> Self { - let mut set = IndexSet::with_capacity_and_hasher(1, Default::default()); - set.insert(Default::default()); - Self(set) + Self::with_capacity(1) } /// Retrieve the key corresponding to the default store, without any hash or equality lookup. @@ -126,11 +124,14 @@ where } } + /// Create an interner with enough space to hold `capacity` entries. + /// + /// Note that the default item of the interner is always allocated and given a key immediately, + /// which will use one slot of the capacity. pub fn with_capacity(capacity: usize) -> Self { - Self(IndexSet::with_capacity_and_hasher( - capacity, - ::ahash::RandomState::new(), - )) + let mut set = IndexSet::with_capacity_and_hasher(capacity, ::ahash::RandomState::new()); + set.insert(Default::default()); + Self(set) } } @@ -196,3 +197,21 @@ where } } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn default_key_exists() { + let mut interner = Interner::<[u32]>::new(); + assert_eq!(interner.get_default(), interner.get_default()); + assert_eq!(interner.get(interner.get_default()), &[]); + assert_eq!(interner.insert_owned(Vec::new()), interner.get_default()); + assert_eq!(interner.insert(&[]), interner.get_default()); + + let capacity = Interner::::with_capacity(4); + assert_eq!(capacity.get_default(), capacity.get_default()); + assert_eq!(capacity.get(capacity.get_default()), ""); + } +} From 8606f058c85e065e8549516339491e4e666de175 Mon Sep 17 00:00:00 2001 From: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:20:17 +0300 Subject: [PATCH 50/85] Port RemoveDiagonalGatesBeforeMeasure to rust (#13065) * add rust code for remove_diagonal_gates_before_measure * replace python code by rust code for remove_diagonal_gates_brefore_measure * make some dag_circuit functions public * fix some of the tests failures * fix another failing test, add more diagonal gates * add tests for added diagonal gates: p, cp, cs, csdg * make the lists of diagonal gates into static arrays * formatting * change nodes_to_remove type to Vec * remove the HashSet following review * add CCZ diagonal gate * add tests for CCZ diagonal gate * add release notes * fix lint --- crates/accelerate/src/lib.rs | 1 + .../remove_diagonal_gates_before_measure.rs | 107 ++++++++++++++ crates/circuit/src/dag_circuit.rs | 4 +- crates/pyext/src/lib.rs | 8 +- qiskit/__init__.py | 3 + .../remove_diagonal_gates_before_measure.py | 38 +---- ...gates-before-measure-86abe39e46d5dad5.yaml | 8 + ...st_remove_diagonal_gates_before_measure.py | 137 +++++++++++++++++- 8 files changed, 269 insertions(+), 37 deletions(-) create mode 100644 crates/accelerate/src/remove_diagonal_gates_before_measure.rs create mode 100644 releasenotes/notes/update-remove-diagonal-gates-before-measure-86abe39e46d5dad5.yaml diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 6561dd258614..e8760ee2c616 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -26,6 +26,7 @@ pub mod isometry; pub mod nlayout; pub mod optimize_1q_gates; pub mod pauli_exp_val; +pub mod remove_diagonal_gates_before_measure; pub mod results; pub mod sabre; pub mod sampled_exp_val; diff --git a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs new file mode 100644 index 000000000000..10916a77fca8 --- /dev/null +++ b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs @@ -0,0 +1,107 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +/// Remove diagonal gates (including diagonal 2Q gates) before a measurement. +use pyo3::prelude::*; + +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType}; +use qiskit_circuit::operations::Operation; +use qiskit_circuit::operations::StandardGate; + +/// Run the RemoveDiagonalGatesBeforeMeasure pass on `dag`. +/// Args: +/// dag (DAGCircuit): the DAG to be optimized. +/// Returns: +/// DAGCircuit: the optimized DAG. +#[pyfunction] +#[pyo3(name = "remove_diagonal_gates_before_measure")] +fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { + static DIAGONAL_1Q_GATES: [StandardGate; 8] = [ + StandardGate::RZGate, + StandardGate::ZGate, + StandardGate::TGate, + StandardGate::SGate, + StandardGate::TdgGate, + StandardGate::SdgGate, + StandardGate::U1Gate, + StandardGate::PhaseGate, + ]; + static DIAGONAL_2Q_GATES: [StandardGate; 7] = [ + StandardGate::CZGate, + StandardGate::CRZGate, + StandardGate::CU1Gate, + StandardGate::RZZGate, + StandardGate::CPhaseGate, + StandardGate::CSGate, + StandardGate::CSdgGate, + ]; + static DIAGONAL_3Q_GATES: [StandardGate; 1] = [StandardGate::CCZGate]; + + let mut nodes_to_remove = Vec::new(); + for index in dag.op_nodes(true) { + let node = &dag.dag[index]; + let NodeType::Operation(inst) = node else {panic!()}; + + if inst.op.name() == "measure" { + let predecessor = (dag.quantum_predecessors(index)) + .next() + .expect("index is an operation node, so it must have a predecessor."); + + match &dag.dag[predecessor] { + NodeType::Operation(pred_inst) => match pred_inst.standard_gate() { + Some(gate) => { + if DIAGONAL_1Q_GATES.contains(&gate) { + nodes_to_remove.push(predecessor); + } else if DIAGONAL_2Q_GATES.contains(&gate) + || DIAGONAL_3Q_GATES.contains(&gate) + { + let successors = dag.quantum_successors(predecessor); + let remove_s = successors + .map(|s| { + let node_s = &dag.dag[s]; + if let NodeType::Operation(inst_s) = node_s { + inst_s.op.name() == "measure" + } else { + false + } + }) + .all(|ok_to_remove| ok_to_remove); + if remove_s { + nodes_to_remove.push(predecessor); + } + } + } + None => { + continue; + } + }, + _ => { + continue; + } + } + } + } + + for node_to_remove in nodes_to_remove { + if dag.dag.node_weight(node_to_remove).is_some() { + dag.remove_op_node(node_to_remove); + } + } + + Ok(()) +} + +#[pymodule] +pub fn remove_diagonal_gates_before_measure(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(run_remove_diagonal_before_measure))?; + Ok(()) +} diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index fdaa81e3b4ca..381ef25b7a7e 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -5122,7 +5122,7 @@ impl DAGCircuit { } } - fn quantum_predecessors(&self, node: NodeIndex) -> impl Iterator + '_ { + pub fn quantum_predecessors(&self, node: NodeIndex) -> impl Iterator + '_ { self.dag .edges_directed(node, Incoming) .filter_map(|e| match e.weight() { @@ -5132,7 +5132,7 @@ impl DAGCircuit { .unique() } - fn quantum_successors(&self, node: NodeIndex) -> impl Iterator + '_ { + pub fn quantum_successors(&self, node: NodeIndex) -> impl Iterator + '_ { self.dag .edges_directed(node, Outgoing) .filter_map(|e| match e.weight() { diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index fdb2bff9a21d..1478fb367a13 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -17,7 +17,8 @@ use qiskit_accelerate::{ commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, isometry::isometry, nlayout::nlayout, - optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, results::results, + optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, + remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, target_transpiler::target, two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, @@ -50,6 +51,11 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, optimize_1q_gates, "optimize_1q_gates")?; add_submodule(m, pauli_expval, "pauli_expval")?; add_submodule(m, synthesis, "synthesis")?; + add_submodule( + m, + remove_diagonal_gates_before_measure, + "remove_diagonal_gates_before_measure", + )?; add_submodule(m, results, "results")?; add_submodule(m, sabre, "sabre")?; add_submodule(m, sampled_exp_val, "sampled_exp_val")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 38a9f5952425..d9979c9d4d92 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -74,6 +74,9 @@ sys.modules["qiskit._accelerate.pauli_expval"] = _accelerate.pauli_expval sys.modules["qiskit._accelerate.qasm2"] = _accelerate.qasm2 sys.modules["qiskit._accelerate.qasm3"] = _accelerate.qasm3 +sys.modules["qiskit._accelerate.remove_diagonal_gates_before_measure"] = ( + _accelerate.remove_diagonal_gates_before_measure +) sys.modules["qiskit._accelerate.results"] = _accelerate.results sys.modules["qiskit._accelerate.sabre"] = _accelerate.sabre sys.modules["qiskit._accelerate.sampled_exp_val"] = _accelerate.sampled_exp_val diff --git a/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py b/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py index be4c79aa47e6..3f72cb4a5cc0 100644 --- a/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py +++ b/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py @@ -12,24 +12,13 @@ """Remove diagonal gates (including diagonal 2Q gates) before a measurement.""" -from qiskit.circuit import Measure -from qiskit.circuit.library.standard_gates import ( - RZGate, - ZGate, - TGate, - SGate, - TdgGate, - SdgGate, - U1Gate, - CZGate, - CRZGate, - CU1Gate, - RZZGate, -) -from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.utils import control_flow +from qiskit._accelerate.remove_diagonal_gates_before_measure import ( + remove_diagonal_gates_before_measure, +) + class RemoveDiagonalGatesBeforeMeasure(TransformationPass): """Remove diagonal gates (including diagonal 2Q gates) before a measurement. @@ -48,22 +37,5 @@ def run(self, dag): Returns: DAGCircuit: the optimized DAG. """ - diagonal_1q_gates = (RZGate, ZGate, TGate, SGate, TdgGate, SdgGate, U1Gate) - diagonal_2q_gates = (CZGate, CRZGate, CU1Gate, RZZGate) - - nodes_to_remove = set() - for measure in dag.op_nodes(Measure): - predecessor = next(dag.quantum_predecessors(measure)) - - if isinstance(predecessor, DAGOpNode) and isinstance(predecessor.op, diagonal_1q_gates): - nodes_to_remove.add(predecessor) - - if isinstance(predecessor, DAGOpNode) and isinstance(predecessor.op, diagonal_2q_gates): - successors = dag.quantum_successors(predecessor) - if all(isinstance(s, DAGOpNode) and isinstance(s.op, Measure) for s in successors): - nodes_to_remove.add(predecessor) - - for node_to_remove in nodes_to_remove: - dag.remove_op_node(node_to_remove) - + remove_diagonal_gates_before_measure(dag) return dag diff --git a/releasenotes/notes/update-remove-diagonal-gates-before-measure-86abe39e46d5dad5.yaml b/releasenotes/notes/update-remove-diagonal-gates-before-measure-86abe39e46d5dad5.yaml new file mode 100644 index 000000000000..294b4ed5bbae --- /dev/null +++ b/releasenotes/notes/update-remove-diagonal-gates-before-measure-86abe39e46d5dad5.yaml @@ -0,0 +1,8 @@ +--- +features_transpiler: + - | + The :class:`.RemoveDiagonalGatesBeforeMeasure` transpiler pass has been upgraded to + include more diagonal gates: :class:`.PhaseGate`, :class:`.CPhaseGate`, + :class:`.CSGate`, :class:`.CSdgGate` and :class:`.CCZGate`. + In addition, the code of the :class:`.RemoveDiagonalGatesBeforeMeasure` was ported to Rust, + and is now x20 faster for a 20 qubit circuit. diff --git a/test/python/transpiler/test_remove_diagonal_gates_before_measure.py b/test/python/transpiler/test_remove_diagonal_gates_before_measure.py index 499bc86d9cf2..474a586448b8 100644 --- a/test/python/transpiler/test_remove_diagonal_gates_before_measure.py +++ b/test/python/transpiler/test_remove_diagonal_gates_before_measure.py @@ -50,6 +50,29 @@ def test_optimize_1rz_1measure(self): self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1phase_1measure(self): + """Remove a single PhaseGate + qr0:--P--m-- qr0:--m- + | | + qr1:-----|-- ==> qr1:--|- + | | + cr0:-----.-- cr0:--.- + """ + qr = QuantumRegister(2, "qr") + cr = ClassicalRegister(1, "cr") + circuit = QuantumCircuit(qr, cr) + circuit.p(0.1, qr[0]) + circuit.measure(qr[0], cr[0]) + dag = circuit_to_dag(circuit) + + expected = QuantumCircuit(qr, cr) + expected.measure(qr[0], cr[0]) + + pass_ = RemoveDiagonalGatesBeforeMeasure() + after = pass_.run(dag) + + self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1z_1measure(self): """Remove a single ZGate qr0:--Z--m-- qr0:--m- @@ -74,7 +97,7 @@ def test_optimize_1z_1measure(self): self.assertEqual(circuit_to_dag(expected), after) def test_optimize_1t_1measure(self): - """Remove a single TGate, SGate, TdgGate, SdgGate, U1Gate + """Remove a single TGate qr0:--T--m-- qr0:--m- | | qr1:-----|-- ==> qr1:--|- @@ -298,6 +321,56 @@ def test_optimize_1cz_2measure(self): self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1cs_2measure(self): + """Remove a single CSGate + qr0:-CS--m--- qr0:--m--- + | | | + qr1:--.--|-m- ==> qr1:--|-m- + | | | | + cr0:-----.-.- cr0:--.-.- + """ + qr = QuantumRegister(2, "qr") + cr = ClassicalRegister(1, "cr") + circuit = QuantumCircuit(qr, cr) + circuit.cs(qr[0], qr[1]) + circuit.measure(qr[0], cr[0]) + circuit.measure(qr[1], cr[0]) + dag = circuit_to_dag(circuit) + + expected = QuantumCircuit(qr, cr) + expected.measure(qr[0], cr[0]) + expected.measure(qr[1], cr[0]) + + pass_ = RemoveDiagonalGatesBeforeMeasure() + after = pass_.run(dag) + + self.assertEqual(circuit_to_dag(expected), after) + + def test_optimize_1csdg_2measure(self): + """Remove a single CSdgGate + qr0:-CSdg--m--- qr0:--m--- + | | | + qr1:----.--|-m- ==> qr1:--|-m- + | | | | + cr0:-------.-.- cr0:--.-.- + """ + qr = QuantumRegister(2, "qr") + cr = ClassicalRegister(1, "cr") + circuit = QuantumCircuit(qr, cr) + circuit.csdg(qr[0], qr[1]) + circuit.measure(qr[0], cr[0]) + circuit.measure(qr[1], cr[0]) + dag = circuit_to_dag(circuit) + + expected = QuantumCircuit(qr, cr) + expected.measure(qr[0], cr[0]) + expected.measure(qr[1], cr[0]) + + pass_ = RemoveDiagonalGatesBeforeMeasure() + after = pass_.run(dag) + + self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1crz_2measure(self): """Remove a single CRZGate qr0:-RZ--m--- qr0:--m--- @@ -323,6 +396,31 @@ def test_optimize_1crz_2measure(self): self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1cp_2measure(self): + """Remove a single CPhaseGate + qr0:-CP--m--- qr0:--m--- + | | | + qr1:--.--|-m- ==> qr1:--|-m- + | | | | + cr0:-----.-.- cr0:--.-.- + """ + qr = QuantumRegister(2, "qr") + cr = ClassicalRegister(1, "cr") + circuit = QuantumCircuit(qr, cr) + circuit.cp(0.1, qr[0], qr[1]) + circuit.measure(qr[0], cr[0]) + circuit.measure(qr[1], cr[0]) + dag = circuit_to_dag(circuit) + + expected = QuantumCircuit(qr, cr) + expected.measure(qr[0], cr[0]) + expected.measure(qr[1], cr[0]) + + pass_ = RemoveDiagonalGatesBeforeMeasure() + after = pass_.run(dag) + + self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1cu1_2measure(self): """Remove a single CU1Gate qr0:-CU1-m--- qr0:--m--- @@ -373,6 +471,27 @@ def test_optimize_1rzz_2measure(self): self.assertEqual(circuit_to_dag(expected), after) + def test_optimize_1ccz_3measure(self): + """Remove a single CCZGate""" + qr = QuantumRegister(3, "qr") + cr = ClassicalRegister(1, "cr") + circuit = QuantumCircuit(qr, cr) + circuit.ccz(qr[0], qr[1], qr[2]) + circuit.measure(qr[0], cr[0]) + circuit.measure(qr[1], cr[0]) + circuit.measure(qr[2], cr[0]) + dag = circuit_to_dag(circuit) + + expected = QuantumCircuit(qr, cr) + expected.measure(qr[0], cr[0]) + expected.measure(qr[1], cr[0]) + expected.measure(qr[2], cr[0]) + + pass_ = RemoveDiagonalGatesBeforeMeasure() + after = pass_.run(dag) + + self.assertEqual(circuit_to_dag(expected), after) + class TestRemoveDiagonalGatesBeforeMeasureOveroptimizations(QiskitTestCase): """Test situations where remove_diagonal_gates_before_measure should not optimize""" @@ -401,6 +520,22 @@ def test_optimize_1cz_1measure(self): self.assertEqual(expected, after) + def test_optimize_1ccz_1measure(self): + """Do not remove a CCZGate because measure happens on only one of the wires""" + qr = QuantumRegister(3, "qr") + cr = ClassicalRegister(1, "cr") + circuit = QuantumCircuit(qr, cr) + circuit.ccz(qr[0], qr[1], qr[2]) + circuit.measure(qr[1], cr[0]) + dag = circuit_to_dag(circuit) + + expected = deepcopy(dag) + + pass_ = RemoveDiagonalGatesBeforeMeasure() + after = pass_.run(dag) + + self.assertEqual(expected, after) + def test_do_not_optimize_with_conditional(self): """Diagonal gates with conditionals on a measurement target. See https://github.com/Qiskit/qiskit-terra/pull/2208#issuecomment-487238819 From 9898979d2947340514adca7121ed8eaea75df77f Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Thu, 5 Sep 2024 18:34:48 +0200 Subject: [PATCH 51/85] Restrict `Split2QUnitaries` to run on `UnitaryGate` (#13095) --- .../passes/optimization/split_2q_unitaries.py | 34 +++++++------- .../restrict-split2q-d51d840cc7a7a482.yaml | 8 ++++ .../transpiler/test_split_2q_unitaries.py | 44 +++++++++++-------- 3 files changed, 48 insertions(+), 38 deletions(-) create mode 100644 releasenotes/notes/restrict-split2q-d51d840cc7a7a482.yaml diff --git a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py index 0b1788e5bbe6..1ca53c6c31d2 100644 --- a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py +++ b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py @@ -9,8 +9,8 @@ # Any modifications or derivative works of this code must retain this # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. + """Splits each two-qubit gate in the `dag` into two single-qubit gates, if possible without error.""" -from typing import Optional from qiskit.transpiler.basepasses import TransformationPass from qiskit.circuit.quantumcircuitdata import CircuitInstruction @@ -21,34 +21,30 @@ class Split2QUnitaries(TransformationPass): - """Attempt to splits two-qubit gates in a :class:`.DAGCircuit` into two single-qubit gates + """Attempt to splits two-qubit unitaries in a :class:`.DAGCircuit` into two single-qubit gates. - This pass will analyze all the two qubit gates in the circuit and analyze the gate's unitary - matrix to determine if the gate is actually a product of 2 single qubit gates. In these - cases the 2q gate can be simplified into two single qubit gates and this pass will - perform this optimization and will replace the two qubit gate with two single qubit - :class:`.UnitaryGate`. + This pass will analyze all :class:`.UnitaryGate` instances and determine whether the + matrix is actually a product of 2 single qubit gates. In these cases the 2q gate can be + simplified into two single qubit gates and this pass will perform this optimization and will + replace the two qubit gate with two single qubit :class:`.UnitaryGate`. """ - def __init__(self, fidelity: Optional[float] = 1.0 - 1e-16): - """Split2QUnitaries initializer. - + def __init__(self, fidelity: float = 1.0 - 1e-16): + """ Args: - fidelity (float): Allowed tolerance for splitting two-qubit unitaries and gate decompositions + fidelity: Allowed tolerance for splitting two-qubit unitaries and gate decompositions. """ super().__init__() self.requested_fidelity = fidelity - def run(self, dag: DAGCircuit): + def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Split2QUnitaries pass on `dag`.""" + for node in dag.topological_op_nodes(): - # skip operations without two-qubits and for which we can not determine a potential 1q split - if ( - len(node.cargs) > 0 - or len(node.qargs) != 2 - or node.matrix is None - or node.is_parameterized() - ): + # We only attempt to split UnitaryGate objects, but this could be extended in future + # -- however we need to ensure that we can compile the resulting single-qubit unitaries + # to the supported basis gate set. + if not (len(node.qargs) == 2 and node.op.name == "unitary"): continue decomp = TwoQubitWeylDecomposition(node.matrix, fidelity=self.requested_fidelity) diff --git a/releasenotes/notes/restrict-split2q-d51d840cc7a7a482.yaml b/releasenotes/notes/restrict-split2q-d51d840cc7a7a482.yaml new file mode 100644 index 000000000000..009a97720e30 --- /dev/null +++ b/releasenotes/notes/restrict-split2q-d51d840cc7a7a482.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixed an edge case when transpiling a circuit with ``optimization_level`` 2 or 3 with an + incomplete 1-qubit basis gate set on a circuit containing 2-qubit gates, that can be + implemented as a product of single qubit gates. This bug is resolved by restricting + :class:`.Split2QUnitaries` to consider only :class:`.UnitaryGate` objects. + Fixed `#12970 `__. diff --git a/test/python/transpiler/test_split_2q_unitaries.py b/test/python/transpiler/test_split_2q_unitaries.py index 7fbb93c2419d..f5727bf5313a 100644 --- a/test/python/transpiler/test_split_2q_unitaries.py +++ b/test/python/transpiler/test_split_2q_unitaries.py @@ -18,7 +18,7 @@ import numpy as np from qiskit import QuantumCircuit, QuantumRegister, transpile -from qiskit.circuit.library import UnitaryGate, XGate, ZGate, HGate +from qiskit.circuit.library import UnitaryGate, XGate, ZGate, HGate, CPhaseGate from qiskit.circuit import Parameter, CircuitInstruction, Gate from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.quantum_info import Operator @@ -160,15 +160,11 @@ def test_no_split(self): def test_almost_identity(self): """Test that the pass handles QFT correctly.""" qc = QuantumCircuit(2) - qc.cp(pi * 2 ** -(26), 0, 1) + qc.unitary(CPhaseGate(pi * 2 ** -(26)).to_matrix(), [0, 1]) pm = PassManager() - pm.append(Collect2qBlocks()) - pm.append(ConsolidateBlocks()) pm.append(Split2QUnitaries(fidelity=1.0 - 1e-9)) qc_split = pm.run(qc) pm = PassManager() - pm.append(Collect2qBlocks()) - pm.append(ConsolidateBlocks()) pm.append(Split2QUnitaries()) qc_split2 = pm.run(qc) self.assertEqual(qc_split.num_nonlocal_gates(), 0) @@ -211,19 +207,6 @@ def test_single_q_gates(self): self.assertTrue(CircuitInstruction(ZGate(), qubits=[qr[1]], clbits=[]) in qc.data) self.assertTrue(CircuitInstruction(HGate(), qubits=[qr[2]], clbits=[]) in qc.data) - def test_split_qft(self): - """Test that the pass handles QFT correctly.""" - qc = QuantumCircuit(100) - qc.h(0) - for i in range(qc.num_qubits - 2, 0, -1): - qc.cp(pi * 2 ** -(qc.num_qubits - 1 - i), qc.num_qubits - 1, i) - pm = PassManager() - pm.append(Collect2qBlocks()) - pm.append(ConsolidateBlocks()) - pm.append(Split2QUnitaries()) - qc_split = pm.run(qc) - self.assertEqual(26, qc_split.num_nonlocal_gates()) - def test_gate_no_array(self): """ Test that the pass doesn't fail when the circuit contains a custom gate @@ -260,3 +243,26 @@ def mygate(self, qubit1, qubit2): self.assertTrue( matrix_equal(Operator(qc).data, Operator(qc_split).data, ignore_phase=False) ) + + def test_nosplit_custom(self): + """Test a single custom gate is not split, even if it is a product. + + That is because we cannot guarantee the split gate is valid in a given basis. + Regression test for #12970. + """ + + class MyGate(Gate): + """A custom gate that could be split.""" + + def __init__(self): + super().__init__("mygate", 2, []) + + def to_matrix(self): + return np.eye(4, dtype=complex) + + qc = QuantumCircuit(2) + qc.append(MyGate(), [0, 1]) + + no_split = Split2QUnitaries()(qc) + + self.assertDictEqual({"mygate": 1}, no_split.count_ops()) From 254ba83dc637a22a91cee0a0cd1c453f89ca55da Mon Sep 17 00:00:00 2001 From: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Date: Thu, 5 Sep 2024 18:36:03 -0400 Subject: [PATCH 52/85] Fix documentation for utils.optionals data values (#13098) --- qiskit/utils/optionals.py | 323 ++++++++++++++++++++------------------ 1 file changed, 173 insertions(+), 150 deletions(-) diff --git a/qiskit/utils/optionals.py b/qiskit/utils/optionals.py index f2e6c860faaa..c5d0d69d11a1 100644 --- a/qiskit/utils/optionals.py +++ b/qiskit/utils/optionals.py @@ -25,172 +25,195 @@ Qiskit Components ----------------- -.. list-table:: - :widths: 25 75 +.. py:data:: HAS_AER - * - .. py:data:: HAS_AER - - `Qiskit Aer ` provides high-performance simulators for - the quantum circuits constructed within Qiskit. + `Qiskit Aer ` provides high-performance simulators for + the quantum circuits constructed within Qiskit. - * - .. py:data:: HAS_IBMQ - - The :mod:`Qiskit IBMQ Provider ` is used for accessing IBM Quantum - hardware in the IBM cloud. +.. py:data:: HAS_IBMQ - * - .. py:data:: HAS_IGNIS - - :mod:`Qiskit Ignis ` provides tools for quantum hardware verification, noise - characterization, and error correction. + The :mod:`Qiskit IBMQ Provider ` is used for accessing IBM Quantum + hardware in the IBM cloud. - * - .. py:data:: HAS_TOQM - - `Qiskit TOQM `__ provides transpiler passes - for the `Time-optimal Qubit mapping algorithm `__. +.. py:data:: HAS_IGNIS + + :mod:`Qiskit Ignis ` provides tools for quantum hardware verification, noise + characterization, and error correction. + +.. py:data:: HAS_TOQM + + `Qiskit TOQM `__ provides transpiler passes + for the `Time-optimal Qubit mapping algorithm `__. External Python Libraries ------------------------- -.. list-table:: - :widths: 25 75 - - * - .. py:data:: HAS_CONSTRAINT - - `python-constraint `__ is a - constraint satisfaction problem solver, used in the :class:`~.CSPLayout` transpiler pass. - - * - .. py:data:: HAS_CPLEX - - The `IBM CPLEX Optimizer `__ is a - high-performance mathematical programming solver for linear, mixed-integer and quadratic - programming. This is no longer by Qiskit, but it weas historically and the optional - remains for backwards compatibility. - - * - .. py:data:: HAS_CVXPY - - `CVXPY `__ is a Python package for solving convex optimization - problems. It is required for calculating diamond norms with - :func:`.quantum_info.diamond_norm`. - - * - .. py:data:: HAS_DOCPLEX - - `IBM Decision Optimization CPLEX Modelling - `__ is a library for prescriptive - analysis. Like CPLEX, this is no longer by Qiskit, but it weas historically and the - optional remains for backwards compatibility. - - * - .. py:data:: HAS_FIXTURES - - The test suite has additional features that are available if the optional `fixtures - `__ module is installed. This generally also needs - :data:`HAS_TESTTOOLS` as well. This is generally only needed for Qiskit developers. - - * - .. py:data:: HAS_IPYTHON - - If `the IPython kernel `__ is available, certain additional - visualizations and line magics are made available. - - * - .. py:data:: HAS_IPYWIDGETS - - Monitoring widgets for jobs running on external backends can be provided if `ipywidgets - `__ is available. - - * - .. py:data:: HAS_JAX - - Some methods of gradient calculation within :mod:`.opflow.gradients` require `JAX - `__ for autodifferentiation. - - * - .. py:data:: HAS_JUPYTER - - Some of the tests require a complete `Jupyter `__ installation to test - interactivity features. - - * - .. py:data:: HAS_MATPLOTLIB - - Qiskit provides several visualization tools in the :mod:`.visualization` module. - Almost all of these are built using `Matplotlib `__, which must - be installed in order to use them. - - * - .. py:data:: HAS_NETWORKX - - No longer used by Qiskit. Internally, Qiskit now uses the high-performance `rustworkx - `__ library as a core dependency, and during the - change-over period, it was sometimes convenient to convert things into the Python-only - `NetworkX `__ format. Some tests of application modules, such as - `Qiskit Nature `__ still use NetworkX. - - * - .. py:data:: HAS_NLOPT - - `NLopt `__ is a nonlinear optimization library, - used by the global optimizers in the :mod:`.algorithms.optimizers` module. - - * - .. py:data:: HAS_PIL - - PIL is a Python image-manipulation library. Qiskit actually uses the `pillow - `__ fork of PIL if it is available when generating - certain visualizations, for example of both :class:`.QuantumCircuit` and - :class:`.DAGCircuit` in certain modes. - - * - .. py:data:: HAS_PYDOT - - For some graph visualizations, Qiskit uses `pydot `__ as an - interface to GraphViz (see :data:`HAS_GRAPHVIZ`). - - * - .. py:data:: HAS_PYGMENTS - - Pygments is a code highlighter and formatter used by many environments that involve rich - display of code blocks, including Sphinx and Jupyter. Qiskit uses this when producing rich - output for these environments. - - * - .. py:data:: HAS_PYLATEX - - Various LaTeX-based visualizations, especially the circuit drawers, need access to the - `pylatexenc `__ project to work correctly. - - * - .. py:data:: HAS_QASM3_IMPORT - - The functions :func:`.qasm3.load` and :func:`.qasm3.loads` for importing OpenQASM 3 programs - into :class:`.QuantumCircuit` instances use `an external importer package - `__. - - * - .. py:data:: HAS_SEABORN - - Qiskit provides several visualization tools in the :mod:`.visualization` module. Some - of these are built using `Seaborn `__, which must be installed - in order to use them. - - * - .. py:data:: HAS_SKLEARN - - Some of the gradient functions in :mod:`.opflow.gradients` use regularisation methods from - `Scikit Learn `__. - - * - .. py:data:: HAS_SKQUANT - - Some of the optimisers in :mod:`.algorithms.optimizers` are based on those found in `Scikit - Quant `__, which must be installed to use - them. - - * - .. py:data:: HAS_SQSNOBFIT - - `SQSnobFit `__ is a library for the "stable noisy - optimization by branch and fit" algorithm. It is used by the :class:`.SNOBFIT` optimizer. - - * - .. py:data:: HAS_SYMENGINE - - `Symengine `__ is a fast C++ backend for the - symbolic-manipulation library `Sympy `__. Qiskit uses - special methods from Symengine to accelerate its handling of - :class:`~.circuit.Parameter`\\ s if available. - - * - .. py:data:: HAS_TESTTOOLS - - Qiskit's test suite has more advanced functionality available if the optional - `testtools `__ library is installed. This is generally - only needed for Qiskit developers. - - * - .. py:data:: HAS_TWEEDLEDUM - - `Tweedledum `__ is an extension library for - synthesis and optimization of circuits that may involve classical oracles. Qiskit's - :class:`.PhaseOracle` uses this, which is used in turn by amplification algorithms via - the :class:`.AmplificationProblem`. - - * - .. py:data:: HAS_Z3 - - `Z3 `__ is a theorem prover, used in the - :class:`.CrosstalkAdaptiveSchedule` and :class:`.HoareOptimizer` transpiler passes. +.. py:data:: HAS_CONSTRAINT + + `python-constraint `__ is a + constraint satisfaction problem solver, used in the :class:`~.CSPLayout` transpiler pass. + +.. py:data:: HAS_CPLEX + + The `IBM CPLEX Optimizer `__ is a + high-performance mathematical programming solver for linear, mixed-integer and quadratic + programming. This is no longer by Qiskit, but it weas historically and the optional + remains for backwards compatibility. + +.. py:data:: HAS_CVXPY + + `CVXPY `__ is a Python package for solving convex optimization + problems. It is required for calculating diamond norms with + :func:`.quantum_info.diamond_norm`. + +.. py:data:: HAS_DOCPLEX + + `IBM Decision Optimization CPLEX Modelling + `__ is a library for prescriptive + analysis. Like CPLEX, this is no longer by Qiskit, but it weas historically and the + optional remains for backwards compatibility. + +.. py:data:: HAS_FIXTURES + + The test suite has additional features that are available if the optional `fixtures + `__ module is installed. This generally also needs + :data:`HAS_TESTTOOLS` as well. This is generally only needed for Qiskit developers. + +.. py:data:: HAS_IPYTHON + + If `the IPython kernel `__ is available, certain additional + visualizations and line magics are made available. + +.. py:data:: HAS_IPYWIDGETS + + Monitoring widgets for jobs running on external backends can be provided if `ipywidgets + `__ is available. + +.. py:data:: HAS_JAX + + Some methods of gradient calculation within :mod:`.opflow.gradients` require `JAX + `__ for autodifferentiation. + +.. py:data:: HAS_JUPYTER + + Some of the tests require a complete `Jupyter `__ installation to test + interactivity features. + +.. py:data:: HAS_MATPLOTLIB + + Qiskit provides several visualization tools in the :mod:`.visualization` module. + Almost all of these are built using `Matplotlib `__, which must + be installed in order to use them. + +.. py:data:: HAS_NETWORKX + + No longer used by Qiskit. Internally, Qiskit now uses the high-performance `rustworkx + `__ library as a core dependency, and during the + change-over period, it was sometimes convenient to convert things into the Python-only + `NetworkX `__ format. Some tests of application modules, such as + `Qiskit Nature `__ still use NetworkX. + +.. py:data:: HAS_NLOPT + + `NLopt `__ is a nonlinear optimization library, + used by the global optimizers in the :mod:`.algorithms.optimizers` module. + +.. py:data:: HAS_PIL + + PIL is a Python image-manipulation library. Qiskit actually uses the `pillow + `__ fork of PIL if it is available when generating + certain visualizations, for example of both :class:`.QuantumCircuit` and + :class:`.DAGCircuit` in certain modes. + +.. py:data:: HAS_PYDOT + + For some graph visualizations, Qiskit uses `pydot `__ as an + interface to GraphViz (see :data:`HAS_GRAPHVIZ`). + +.. py:data:: HAS_PYGMENTS + + Pygments is a code highlighter and formatter used by many environments that involve rich + display of code blocks, including Sphinx and Jupyter. Qiskit uses this when producing rich + output for these environments. + +.. py:data:: HAS_PYLATEX + + Various LaTeX-based visualizations, especially the circuit drawers, need access to the + `pylatexenc `__ project to work correctly. + +.. py:data:: HAS_QASM3_IMPORT + + The functions :func:`.qasm3.load` and :func:`.qasm3.loads` for importing OpenQASM 3 programs + into :class:`.QuantumCircuit` instances use `an external importer package + `__. + +.. py:data:: HAS_SEABORN + + Qiskit provides several visualization tools in the :mod:`.visualization` module. Some + of these are built using `Seaborn `__, which must be installed + in order to use them. + +.. py:data:: HAS_SKLEARN + + Some of the gradient functions in :mod:`.opflow.gradients` use regularisation methods from + `Scikit Learn `__. + +.. py:data:: HAS_SKQUANT + + Some of the optimisers in :mod:`.algorithms.optimizers` are based on those found in `Scikit + Quant `__, which must be installed to use + them. + +.. py:data:: HAS_SQSNOBFIT + + `SQSnobFit `__ is a library for the "stable noisy + optimization by branch and fit" algorithm. It is used by the :class:`.SNOBFIT` optimizer. + +.. py:data:: HAS_SYMENGINE + + `Symengine `__ is a fast C++ backend for the + symbolic-manipulation library `Sympy `__. Qiskit uses + special methods from Symengine to accelerate its handling of + :class:`~.circuit.Parameter`\\ s if available. + +.. py:data:: HAS_TESTTOOLS + + Qiskit's test suite has more advanced functionality available if the optional + `testtools `__ library is installed. This is generally + only needed for Qiskit developers. + +.. py:data:: HAS_TWEEDLEDUM + + `Tweedledum `__ is an extension library for + synthesis and optimization of circuits that may involve classical oracles. Qiskit's + :class:`.PhaseOracle` uses this, which is used in turn by amplification algorithms via + the :class:`.AmplificationProblem`. + +.. py:data:: HAS_Z3 + + `Z3 `__ is a theorem prover, used in the + :class:`.CrosstalkAdaptiveSchedule` and :class:`.HoareOptimizer` transpiler passes. External Command-Line Tools --------------------------- -.. list-table:: - :widths: 25 75 +.. py:data:: HAS_GRAPHVIZ + + For some graph visualizations, Qiskit uses the `GraphViz `__ + visualization tool via its ``pydot`` interface (see :data:`HAS_PYDOT`). + +.. py:data:: HAS_PDFLATEX - * - .. py:data:: HAS_GRAPHVIZ - - For some graph visualizations, Qiskit uses the `GraphViz `__ - visualization tool via its ``pydot`` interface (see :data:`HAS_PYDOT`). + Visualization tools that use LaTeX in their output, such as the circuit drawers, require + ``pdflatex`` to be available. You will generally need to ensure that you have a working + LaTeX installation available, and the ``qcircuit.tex`` package. - * - .. py:data:: HAS_PDFLATEX - - Visualization tools that use LaTeX in their output, such as the circuit drawers, require - ``pdflatex`` to be available. You will generally need to ensure that you have a working - LaTeX installation available, and the ``qcircuit.tex`` package. +.. py:data:: HAS_PDFTOCAIRO - * - .. py:data:: HAS_PDFTOCAIRO - - Visualization tools that convert LaTeX-generated files into rasterized images use the - ``pdftocairo`` tool. This is part of the `Poppler suite of PDF tools - `__. + Visualization tools that convert LaTeX-generated files into rasterized images use the + ``pdftocairo`` tool. This is part of the `Poppler suite of PDF tools + `__. Lazy Checker Classes From 8982dbde157eafa8e104495472115f4257a502fa Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 5 Sep 2024 19:00:08 -0400 Subject: [PATCH 53/85] Fully port FilterOpNodes to Rust (#13052) * Fully port FilterOpNodes to Rust This commit ports the FilterOpNodes pass to rust. This pass is exceedingly simple and just runs a filter function over all the op nodes and removes nodes that match the filter. However, the API for the class exposes that filter function interface as a user provided Python callable. So for the current pass we need to retain that python callback. This limits the absolute performance of this pass because we're bottlenecked by calling python. Looking to the future, this commit adds a rust native method to DAGCircuit to perform this filtering with a rust predicate FnMut. It isn't leveraged by the python implementation because of layer mismatch for the efficient rust interface and Python working with `DAGOpNode` objects. A function using that interface is added to filter labeled nodes. In the preset pass manager we only use FilterOpNodes to remove nodes with a specific label (which is used to identify temporary barriers created by qiskit). In a follow up we should consider leveraging this new function to build a new pass specifically for this use case. Fixes #12263 Part of #12208 * Make filter_op_nodes() infallible The filter_op_nodes() method originally returned a Result<()> to handle a predicate that was fallible. This was because the original intent for the method was to use it with Python callbacks in the predicate. But because of differences between the rust API and the Python API this wasn't feasible as was originally planned. So this Result<()> return wasn't used anymore. This commit reworks it to make the filter_op_nodes() infallible and the predicate a user provides also only returns `bool` and not `Result`. * Rename filter_labelled_op to filter_labeled_op --- crates/accelerate/src/filter_op_nodes.rs | 63 +++++++++++++++++++ crates/accelerate/src/lib.rs | 1 + .../remove_diagonal_gates_before_measure.rs | 4 +- crates/circuit/src/dag_circuit.rs | 19 ++++++ crates/circuit/src/packed_instruction.rs | 7 +++ crates/pyext/src/lib.rs | 6 +- qiskit/__init__.py | 1 + .../passes/utils/filter_op_nodes.py | 6 +- 8 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 crates/accelerate/src/filter_op_nodes.rs diff --git a/crates/accelerate/src/filter_op_nodes.rs b/crates/accelerate/src/filter_op_nodes.rs new file mode 100644 index 000000000000..7c41391f3788 --- /dev/null +++ b/crates/accelerate/src/filter_op_nodes.rs @@ -0,0 +1,63 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; + +use qiskit_circuit::dag_circuit::DAGCircuit; +use qiskit_circuit::packed_instruction::PackedInstruction; +use rustworkx_core::petgraph::stable_graph::NodeIndex; + +#[pyfunction] +#[pyo3(name = "filter_op_nodes")] +pub fn py_filter_op_nodes( + py: Python, + dag: &mut DAGCircuit, + predicate: &Bound, +) -> PyResult<()> { + let callable = |node: NodeIndex| -> PyResult { + let dag_op_node = dag.get_node(py, node)?; + predicate.call1((dag_op_node,))?.extract() + }; + let mut remove_nodes: Vec = Vec::new(); + for node in dag.op_nodes(true) { + if !callable(node)? { + remove_nodes.push(node); + } + } + for node in remove_nodes { + dag.remove_op_node(node); + } + Ok(()) +} + +/// Remove any nodes that have the provided label set +/// +/// Args: +/// dag (DAGCircuit): The dag circuit to filter the ops from +/// label (str): The label to filter nodes on +#[pyfunction] +pub fn filter_labeled_op(dag: &mut DAGCircuit, label: String) { + let predicate = |node: &PackedInstruction| -> bool { + match node.label() { + Some(inst_label) => inst_label != label, + None => false, + } + }; + dag.filter_op_nodes(predicate); +} + +pub fn filter_op_nodes_mod(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(py_filter_op_nodes))?; + m.add_wrapped(wrap_pyfunction!(filter_labeled_op))?; + Ok(()) +} diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index e8760ee2c616..78eea97faad0 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -22,6 +22,7 @@ pub mod dense_layout; pub mod edge_collections; pub mod error_map; pub mod euler_one_qubit_decomposer; +pub mod filter_op_nodes; pub mod isometry; pub mod nlayout; pub mod optimize_1q_gates; diff --git a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs index 10916a77fca8..cf2c738f131a 100644 --- a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs +++ b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs @@ -49,7 +49,9 @@ fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { let mut nodes_to_remove = Vec::new(); for index in dag.op_nodes(true) { let node = &dag.dag[index]; - let NodeType::Operation(inst) = node else {panic!()}; + let NodeType::Operation(inst) = node else { + panic!() + }; if inst.op.name() == "measure" { let predecessor = (dag.quantum_predecessors(index)) diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 381ef25b7a7e..32b3a77ed24c 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -5794,6 +5794,25 @@ impl DAGCircuit { } } + // Filter any nodes that don't match a given predicate function + pub fn filter_op_nodes(&mut self, mut predicate: F) + where + F: FnMut(&PackedInstruction) -> bool, + { + let mut remove_nodes: Vec = Vec::new(); + for node in self.op_nodes(true) { + let NodeType::Operation(op) = &self.dag[node] else { + unreachable!() + }; + if !predicate(op) { + remove_nodes.push(node); + } + } + for node in remove_nodes { + self.remove_op_node(node); + } + } + pub fn op_nodes_by_py_type<'a>( &'a self, op: &'a Bound, diff --git a/crates/circuit/src/packed_instruction.rs b/crates/circuit/src/packed_instruction.rs index 77ca0c6c02dd..df8f9801314a 100644 --- a/crates/circuit/src/packed_instruction.rs +++ b/crates/circuit/src/packed_instruction.rs @@ -553,6 +553,13 @@ impl PackedInstruction { .and_then(|extra| extra.condition.as_ref()) } + #[inline] + pub fn label(&self) -> Option<&str> { + self.extra_attrs + .as_ref() + .and_then(|extra| extra.label.as_deref()) + } + /// Build a reference to the Python-space operation object (the `Gate`, etc) packed into this /// instruction. This may construct the reference if the `PackedInstruction` is a standard /// gate with no already stored operation. diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 1478fb367a13..49e44bffa2ec 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -16,8 +16,9 @@ use qiskit_accelerate::{ circuit_library::circuit_library, commutation_analysis::commutation_analysis, commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, error_map::error_map, - euler_one_qubit_decomposer::euler_one_qubit_decomposer, isometry::isometry, nlayout::nlayout, - optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, + euler_one_qubit_decomposer::euler_one_qubit_decomposer, filter_op_nodes::filter_op_nodes_mod, + isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, + pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, @@ -46,6 +47,7 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, dense_layout, "dense_layout")?; add_submodule(m, error_map, "error_map")?; add_submodule(m, euler_one_qubit_decomposer, "euler_one_qubit_decomposer")?; + add_submodule(m, filter_op_nodes_mod, "filter_op_nodes")?; add_submodule(m, isometry, "isometry")?; add_submodule(m, nlayout, "nlayout")?; add_submodule(m, optimize_1q_gates, "optimize_1q_gates")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index d9979c9d4d92..3cc10bf96a31 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -92,6 +92,7 @@ sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase +sys.modules["qiskit._accelerate.filter_op_nodes"] = _accelerate.filter_op_nodes from qiskit.exceptions import QiskitError, MissingOptionalLibraryError diff --git a/qiskit/transpiler/passes/utils/filter_op_nodes.py b/qiskit/transpiler/passes/utils/filter_op_nodes.py index 344d2280e3f4..75b824332aee 100644 --- a/qiskit/transpiler/passes/utils/filter_op_nodes.py +++ b/qiskit/transpiler/passes/utils/filter_op_nodes.py @@ -18,6 +18,8 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.utils import control_flow +from qiskit._accelerate.filter_op_nodes import filter_op_nodes + class FilterOpNodes(TransformationPass): """Remove all operations that match a filter function @@ -59,7 +61,5 @@ def __init__(self, predicate: Callable[[DAGOpNode], bool]): @control_flow.trivial_recurse def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the RemoveBarriers pass on `dag`.""" - for node in dag.op_nodes(): - if not self.predicate(node): - dag.remove_op_node(node) + filter_op_nodes(dag, self.predicate) return dag From b80b454c8763f650b134a514faf959aee51d9dd3 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 5 Sep 2024 19:29:26 -0400 Subject: [PATCH 54/85] Fix clippy failures with Rust 1.81.0 (#13100) The recently released Rust 1.81.0 introduced some new on by default clippy rules and these rules are flagging issues in the rust code in the library. While we use Rust 1.70 for clippy in CI and these won't cause failures until we raise our MSRV to >= 1.81.0 these clippy warnings/failures are still good to fix as the either make the code more consise and/or efficient. This commit fixes these issues identified by clippy. --- crates/accelerate/src/results/marginalization.rs | 9 ++------- crates/circuit/src/operations.rs | 5 +---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/crates/accelerate/src/results/marginalization.rs b/crates/accelerate/src/results/marginalization.rs index 5260287e771d..b9e7ec4ba65c 100644 --- a/crates/accelerate/src/results/marginalization.rs +++ b/crates/accelerate/src/results/marginalization.rs @@ -26,16 +26,11 @@ fn marginalize( indices: Option>, ) -> HashMap { let mut out_counts: HashMap = HashMap::with_capacity(counts.len()); - let clbit_size = counts - .keys() - .next() - .unwrap() - .replace(|c| c == '_' || c == ' ', "") - .len(); + let clbit_size = counts.keys().next().unwrap().replace(['_', ' '], "").len(); let all_indices: Vec = (0..clbit_size).collect(); counts .iter() - .map(|(k, v)| (k.replace(|c| c == '_' || c == ' ', ""), *v)) + .map(|(k, v)| (k.replace(['_', ' '], ""), *v)) .for_each(|(k, v)| match &indices { Some(indices) => { if all_indices == *indices { diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index 8cc2256af518..a3fd2fc83c3d 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -2225,10 +2225,7 @@ impl Operation for PyGate { fn standard_gate(&self) -> Option { Python::with_gil(|py| -> Option { match self.gate.getattr(py, intern!(py, "_standard_gate")) { - Ok(stdgate) => match stdgate.extract(py) { - Ok(out_gate) => out_gate, - Err(_) => None, - }, + Ok(stdgate) => stdgate.extract(py).unwrap_or_default(), Err(_) => None, } }) From 1a4193a1c52f73f081407b8f234da1b154198da6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:08:35 +0000 Subject: [PATCH 55/85] Bump bytemuck from 1.17.1 to 1.18.0 (#13105) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.17.1 to 1.18.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.17.1...v1.18.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7921b7aeba83..9745b67b7405 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" dependencies = [ "bytemuck_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 4f7f8ad86b96..2f5fd8ce077b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ license = "Apache-2.0" # # Each crate can add on specific features freely as it inherits. [workspace.dependencies] -bytemuck = "1.17" +bytemuck = "1.18" indexmap.version = "2.5.0" hashbrown.version = "0.14.5" num-bigint = "0.4" From 7c409123a369c7df0b86f99ae00fefd41bc142fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:34:52 +0000 Subject: [PATCH 56/85] Bump faer from 0.19.2 to 0.19.3 (#13104) Bumps [faer](https://github.com/sarah-ek/faer-rs) from 0.19.2 to 0.19.3. - [Changelog](https://github.com/sarah-ek/faer-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/sarah-ek/faer-rs/commits) --- updated-dependencies: - dependency-name: faer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/accelerate/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9745b67b7405..d00620630e79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,9 +345,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "faer" -version = "0.19.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8894ad9275f1fd708e2f114f4059e80057ad3cc150b77a3f8a7991dd47ab37" +checksum = "0821d176d7fd17ea91d8a5ce84c56413e11410f404e418bfd205acf40184d819" dependencies = [ "bytemuck", "coe-rs", diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index f444a5c8ed66..4b5c18e5eb93 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -20,7 +20,7 @@ num-traits = "0.2" num-complex.workspace = true rustworkx-core.workspace = true num-bigint.workspace = true -faer = "0.19.2" +faer = "0.19.3" itertools.workspace = true qiskit-circuit.workspace = true thiserror.workspace = true From 3d4bab2be7fd09f6dcf734a3386355cae6cded39 Mon Sep 17 00:00:00 2001 From: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:26:48 -0400 Subject: [PATCH 57/85] Add method to add instructions to a DAGCircuit from an iterator of PackedInstruction (#13032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial: Add add_from_iter method to DAGCircuit - Introduce a method that adds a chain of `PackedInstruction` continuously avoiding the re-linking of each bit's output-node until the very end of the iterator. - TODO: Add handling of vars - Add header for a `from_iter` function that will create a `DAGCircuit` based on a chain of `PackedInstruction`. * Fix: leverage new methods in layers - Fix incorrect re-insertion of last_node. * Fix: Keep track of Vars for add_from_iter - Remove `from_iter` * Fix: Incorrect modification of last nodes in `add_from_iter`. - Use `entry` api to either modify or insert a value if missing. * Fix: Cycling edges in when adding vars. - A bug that adds duplicate edges to vars has been temporarily fixed. However, the root of this problem hasn't been found yet. A proper fix is pending. For now skip those instances. * Fix: Remove set collecting all nodes to be connected. - A set collecting all the new nodes to connect with a new node was preventing additional wires to connect to subsequent nodes. * Fix: Adapt to #13033 * Refactor: `add_from_iter` is now called `extend` to stick with `Rust` nomenclature. * Fix docstring - Caught by @ElePT Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Fix: Remove duplicate vars check * Fix: Corrections from code review. - Use Entry API to modify last nodes in the var. - Build new_nodes with an allocated vec. - Add comment explaining the removal of the edge between the output node and its predecessor. * Fix: Improper use of `Entry API`. - Use `or_insert_with` instead of `or_insert` to perform actions before inserting a value. --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- crates/circuit/src/dag_circuit.rs | 141 +++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 3 deletions(-) diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 32b3a77ed24c..4d41660708d3 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -4350,9 +4350,7 @@ def _format(operand): let mut new_layer = self.copy_empty_like(py, vars_mode)?; - for (node, _) in op_nodes { - new_layer.push_back(py, node.clone())?; - } + new_layer.extend(py, op_nodes.iter().map(|(inst, _)| (*inst).clone()))?; let new_layer_op_nodes = new_layer.op_nodes(false).filter_map(|node_index| { match new_layer.dag.node_weight(node_index) { @@ -6366,6 +6364,143 @@ impl DAGCircuit { Err(DAGCircuitError::new_err("Specified node is not an op node")) } } + + /// Extends the DAG with valid instances of [PackedInstruction] + pub fn extend(&mut self, py: Python, iter: I) -> PyResult> + where + I: IntoIterator, + { + // Create HashSets to keep track of each bit/var's last node + let mut qubit_last_nodes: HashMap = HashMap::default(); + let mut clbit_last_nodes: HashMap = HashMap::default(); + // TODO: Refactor once Vars are in rust + // Dict [ Var: (int, VarWeight)] + let vars_last_nodes: Bound = PyDict::new_bound(py); + + // Consume into iterator to obtain size hint + let iter = iter.into_iter(); + // Store new nodes to return + let mut new_nodes = Vec::with_capacity(iter.size_hint().1.unwrap_or_default()); + for instr in iter { + let op_name = instr.op.name(); + let (all_cbits, vars): (Vec, Option>) = { + if self.may_have_additional_wires(py, &instr) { + let mut clbits: HashSet = + HashSet::from_iter(self.cargs_interner.get(instr.clbits).iter().copied()); + let (additional_clbits, additional_vars) = + self.additional_wires(py, instr.op.view(), instr.condition())?; + for clbit in additional_clbits { + clbits.insert(clbit); + } + (clbits.into_iter().collect(), Some(additional_vars)) + } else { + (self.cargs_interner.get(instr.clbits).to_vec(), None) + } + }; + + // Increment the operation count + self.increment_op(op_name); + + // Get the correct qubit indices + let qubits_id = instr.qubits; + + // Insert op-node to graph. + let new_node = self.dag.add_node(NodeType::Operation(instr)); + new_nodes.push(new_node); + + // Check all the qubits in this instruction. + for qubit in self.qargs_interner.get(qubits_id) { + // Retrieve each qubit's last node + let qubit_last_node = *qubit_last_nodes.entry(*qubit).or_insert_with(|| { + // If the qubit is not in the last nodes collection, the edge between the output node and its predecessor. + // Then, store the predecessor's NodeIndex in the last nodes collection. + let output_node = self.qubit_io_map[qubit.0 as usize][1]; + let (edge_id, predecessor_node) = self + .dag + .edges_directed(output_node, Incoming) + .next() + .map(|edge| (edge.id(), edge.source())) + .unwrap(); + self.dag.remove_edge(edge_id); + predecessor_node + }); + qubit_last_nodes + .entry(*qubit) + .and_modify(|val| *val = new_node); + self.dag + .add_edge(qubit_last_node, new_node, Wire::Qubit(*qubit)); + } + + // Check all the clbits in this instruction. + for clbit in all_cbits { + let clbit_last_node = *clbit_last_nodes.entry(clbit).or_insert_with(|| { + // If the qubit is not in the last nodes collection, the edge between the output node and its predecessor. + // Then, store the predecessor's NodeIndex in the last nodes collection. + let output_node = self.clbit_io_map[clbit.0 as usize][1]; + let (edge_id, predecessor_node) = self + .dag + .edges_directed(output_node, Incoming) + .next() + .map(|edge| (edge.id(), edge.source())) + .unwrap(); + self.dag.remove_edge(edge_id); + predecessor_node + }); + clbit_last_nodes + .entry(clbit) + .and_modify(|val| *val = new_node); + self.dag + .add_edge(clbit_last_node, new_node, Wire::Clbit(clbit)); + } + + // If available, check all the vars in this instruction + for var in vars.iter().flatten() { + let var_last_node = if let Some(result) = vars_last_nodes.get_item(var)? { + let node: usize = result.extract()?; + vars_last_nodes.del_item(var)?; + NodeIndex::new(node) + } else { + // If the var is not in the last nodes collection, the edge between the output node and its predecessor. + // Then, store the predecessor's NodeIndex in the last nodes collection. + let output_node = self.var_output_map.get(py, var).unwrap(); + let (edge_id, predecessor_node) = self + .dag + .edges_directed(output_node, Incoming) + .next() + .map(|edge| (edge.id(), edge.source())) + .unwrap(); + self.dag.remove_edge(edge_id); + predecessor_node + }; + + vars_last_nodes.set_item(var, new_node.index())?; + self.dag + .add_edge(var_last_node, new_node, Wire::Var(var.clone_ref(py))); + } + } + + // Add the output_nodes back to qargs + for (qubit, node) in qubit_last_nodes { + let output_node = self.qubit_io_map[qubit.0 as usize][1]; + self.dag.add_edge(node, output_node, Wire::Qubit(qubit)); + } + + // Add the output_nodes back to cargs + for (clbit, node) in clbit_last_nodes { + let output_node = self.clbit_io_map[clbit.0 as usize][1]; + self.dag.add_edge(node, output_node, Wire::Clbit(clbit)); + } + + // Add the output_nodes back to vars + for item in vars_last_nodes.items() { + let (var, node): (PyObject, usize) = item.extract()?; + let output_node = self.var_output_map.get(py, &var).unwrap(); + self.dag + .add_edge(NodeIndex::new(node), output_node, Wire::Var(var)); + } + + Ok(new_nodes) + } } /// Add to global phase. Global phase can only be Float or ParameterExpression so this From 41dc41888ec60a7aab9b93aaa0aaebb5d4711a77 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 6 Sep 2024 16:52:42 -0400 Subject: [PATCH 58/85] Fully port CheckMap to Rust (#13030) * Fully port CheckMap to Rust This commit migrates the entirety of the CheckMap analysis pass to Rust. The pass operates solely in the rust domain and returns an `Option<(String, [u32; 2])>` to Python which is used to set the two property set fields appropriately. All the analysis of the dag is done in Rust. There is still Python interaction required though because control flow operations are only defined in Python. However the interaction is minimal and only to get the circuits for control flow blocks and converting them into DAGs (at least until #13001 is complete). This commit is based on top of #12959 and will need to be rebased after that merges. Closes #12251 Part of #12208 * Use a Vec for wire_map instead of a HashMap This commit switches to using a Vec for the internal wire_map used to map control flow qubits. A HashMap was originally used because in Python a dictionary is used. However, in the rust domain the inner qubits are contiguous integers starting from 0 so a Vec can be used for better performance in the case we have control flow. * Update crates/accelerate/src/check_map.rs Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> --------- Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> --- crates/accelerate/src/check_map.rs | 98 +++++++++++++++++++++ crates/accelerate/src/lib.rs | 1 + crates/pyext/src/lib.rs | 13 +-- qiskit/__init__.py | 1 + qiskit/transpiler/passes/utils/check_map.py | 33 +++---- 5 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 crates/accelerate/src/check_map.rs diff --git a/crates/accelerate/src/check_map.rs b/crates/accelerate/src/check_map.rs new file mode 100644 index 000000000000..8ebf50cd372d --- /dev/null +++ b/crates/accelerate/src/check_map.rs @@ -0,0 +1,98 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use hashbrown::HashSet; +use pyo3::intern; +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; + +use qiskit_circuit::circuit_data::CircuitData; +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType}; +use qiskit_circuit::imports::CIRCUIT_TO_DAG; +use qiskit_circuit::operations::{Operation, OperationRef}; +use qiskit_circuit::Qubit; + +fn recurse<'py>( + py: Python<'py>, + dag: &'py DAGCircuit, + edge_set: &'py HashSet<[u32; 2]>, + wire_map: Option<&'py [Qubit]>, +) -> PyResult> { + let check_qubits = |qubits: &[Qubit]| -> bool { + match wire_map { + Some(wire_map) => { + let mapped_bits = [ + wire_map[qubits[0].0 as usize], + wire_map[qubits[1].0 as usize], + ]; + edge_set.contains(&[mapped_bits[0].into(), mapped_bits[1].into()]) + } + None => edge_set.contains(&[qubits[0].into(), qubits[1].into()]), + } + }; + for node in dag.op_nodes(false) { + if let NodeType::Operation(inst) = &dag.dag[node] { + let qubits = dag.get_qargs(inst.qubits); + if inst.op.control_flow() { + if let OperationRef::Instruction(py_inst) = inst.op.view() { + let raw_blocks = py_inst.instruction.getattr(py, "blocks")?; + let circuit_to_dag = CIRCUIT_TO_DAG.get_bound(py); + for raw_block in raw_blocks.bind(py).iter().unwrap() { + let block_obj = raw_block?; + let block = block_obj + .getattr(intern!(py, "_data"))? + .downcast::()? + .borrow(); + let new_dag: DAGCircuit = + circuit_to_dag.call1((block_obj.clone(),))?.extract()?; + let wire_map = (0..block.num_qubits()) + .map(|inner| { + let outer = qubits[inner]; + match wire_map { + Some(wire_map) => wire_map[outer.0 as usize], + None => outer, + } + }) + .collect::>(); + let res = recurse(py, &new_dag, edge_set, Some(&wire_map))?; + if res.is_some() { + return Ok(res); + } + } + } + } else if qubits.len() == 2 + && (dag.calibrations_empty() || !dag.has_calibration_for_index(py, node)?) + && !check_qubits(qubits) + { + return Ok(Some(( + inst.op.name().to_string(), + [qubits[0].0, qubits[1].0], + ))); + } + } + } + Ok(None) +} + +#[pyfunction] +pub fn check_map( + py: Python, + dag: &DAGCircuit, + edge_set: HashSet<[u32; 2]>, +) -> PyResult> { + recurse(py, dag, &edge_set, None) +} + +pub fn check_map_mod(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(check_map))?; + Ok(()) +} diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 78eea97faad0..f11f28071e2c 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -14,6 +14,7 @@ use std::env; use pyo3::import_exception; +pub mod check_map; pub mod circuit_library; pub mod commutation_analysis; pub mod commutation_checker; diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 49e44bffa2ec..ec883c69c3f1 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -13,12 +13,12 @@ use pyo3::prelude::*; use qiskit_accelerate::{ - circuit_library::circuit_library, commutation_analysis::commutation_analysis, - commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, - dense_layout::dense_layout, error_map::error_map, - euler_one_qubit_decomposer::euler_one_qubit_decomposer, filter_op_nodes::filter_op_nodes_mod, - isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, - pauli_exp_val::pauli_expval, + check_map::check_map_mod, circuit_library::circuit_library, + commutation_analysis::commutation_analysis, commutation_checker::commutation_checker, + convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, + error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, + filter_op_nodes::filter_op_nodes_mod, isometry::isometry, nlayout::nlayout, + optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, @@ -43,6 +43,7 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, qiskit_qasm2::qasm2, "qasm2")?; add_submodule(m, qiskit_qasm3::qasm3, "qasm3")?; add_submodule(m, circuit_library, "circuit_library")?; + add_submodule(m, check_map_mod, "check_map")?; add_submodule(m, convert_2q_block_matrix, "convert_2q_block_matrix")?; add_submodule(m, dense_layout, "dense_layout")?; add_submodule(m, error_map, "error_map")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 3cc10bf96a31..386b9cd082da 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -92,6 +92,7 @@ sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase +sys.modules["qiskit._accelerate.check_map"] = _accelerate.check_map sys.modules["qiskit._accelerate.filter_op_nodes"] = _accelerate.filter_op_nodes from qiskit.exceptions import QiskitError, MissingOptionalLibraryError diff --git a/qiskit/transpiler/passes/utils/check_map.py b/qiskit/transpiler/passes/utils/check_map.py index bd78c65de5f4..4048d93df22c 100644 --- a/qiskit/transpiler/passes/utils/check_map.py +++ b/qiskit/transpiler/passes/utils/check_map.py @@ -14,7 +14,8 @@ from qiskit.transpiler.basepasses import AnalysisPass from qiskit.transpiler.target import Target -from qiskit.converters import circuit_to_dag + +from qiskit._accelerate import check_map class CheckMap(AnalysisPass): @@ -67,25 +68,11 @@ def run(self, dag): if not self.qargs: self.property_set[self.property_set_field] = True return - wire_map = {bit: index for index, bit in enumerate(dag.qubits)} - self.property_set[self.property_set_field] = self._recurse(dag, wire_map) - - def _recurse(self, dag, wire_map) -> bool: - for node in dag.op_nodes(include_directives=False): - if node.is_control_flow(): - for block in node.op.blocks: - inner_wire_map = { - inner: wire_map[outer] for inner, outer in zip(block.qubits, node.qargs) - } - if not self._recurse(circuit_to_dag(block), inner_wire_map): - return False - elif ( - len(node.qargs) == 2 - and not dag.has_calibration_for(node) - and (wire_map[node.qargs[0]], wire_map[node.qargs[1]]) not in self.qargs - ): - self.property_set["check_map_msg"] = ( - f"{node.name}({wire_map[node.qargs[0]]}, {wire_map[node.qargs[1]]}) failed" - ) - return False - return True + res = check_map.check_map(dag, self.qargs) + if res is None: + self.property_set[self.property_set_field] = True + return + self.property_set[self.property_set_field] = False + self.property_set["check_map_msg"] = ( + f"{res[0]}({dag.qubits[res[1][0]]}, {dag.qubits[res[1][1]]}) failed" + ) From 94ba19e9fbbbdc0176b235e907354c0fab7468f5 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 6 Sep 2024 19:08:47 -0400 Subject: [PATCH 59/85] Fully port InverseCancellation to Rust (#13013) * Fully port InverseCancellation to Rust This commit builds off of #12959 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for handling parameter expressions. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different inverse gates/pairs so we should be able to the throughput of the pass by leveraging multithreading to handle each inverse option in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Fixes #12271 Part of #12208 * Remove temporary variable for chunk empty check * Destructure gate pairs * Rework short circuit logic --- crates/accelerate/src/inverse_cancellation.rs | 191 ++++++++++++++++++ crates/accelerate/src/lib.rs | 1 + crates/circuit/src/dag_circuit.rs | 94 +++++---- crates/pyext/src/lib.rs | 6 +- qiskit/__init__.py | 1 + .../optimization/inverse_cancellation.py | 101 +-------- 6 files changed, 260 insertions(+), 134 deletions(-) create mode 100644 crates/accelerate/src/inverse_cancellation.rs diff --git a/crates/accelerate/src/inverse_cancellation.rs b/crates/accelerate/src/inverse_cancellation.rs new file mode 100644 index 000000000000..0b3404c92ffb --- /dev/null +++ b/crates/accelerate/src/inverse_cancellation.rs @@ -0,0 +1,191 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use ahash::RandomState; +use hashbrown::HashSet; +use indexmap::IndexMap; +use pyo3::prelude::*; +use rustworkx_core::petgraph::stable_graph::NodeIndex; + +use qiskit_circuit::circuit_instruction::OperationFromPython; +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType}; +use qiskit_circuit::operations::Operation; +use qiskit_circuit::packed_instruction::PackedInstruction; + +fn gate_eq(py: Python, gate_a: &PackedInstruction, gate_b: &OperationFromPython) -> PyResult { + if gate_a.op.name() != gate_b.operation.name() { + return Ok(false); + } + let a_params = gate_a.params_view(); + if a_params.len() != gate_b.params.len() { + return Ok(false); + } + let mut param_eq = true; + for (a, b) in a_params.iter().zip(&gate_b.params) { + if !a.is_close(py, b, 1e-10)? { + param_eq = false; + break; + } + } + Ok(param_eq) +} + +fn run_on_self_inverse( + py: Python, + dag: &mut DAGCircuit, + op_counts: &IndexMap, + self_inverse_gate_names: HashSet, + self_inverse_gates: Vec, +) -> PyResult<()> { + if !self_inverse_gate_names + .iter() + .any(|name| op_counts.contains_key(name)) + { + return Ok(()); + } + for gate in self_inverse_gates { + let gate_count = op_counts.get(gate.operation.name()).unwrap_or(&0); + if *gate_count <= 1 { + continue; + } + let mut collect_set: HashSet = HashSet::with_capacity(1); + collect_set.insert(gate.operation.name().to_string()); + let gate_runs: Vec> = dag.collect_runs(collect_set).unwrap().collect(); + for gate_cancel_run in gate_runs { + let mut partitions: Vec> = Vec::new(); + let mut chunk: Vec = Vec::new(); + let max_index = gate_cancel_run.len() - 1; + for (i, cancel_gate) in gate_cancel_run.iter().enumerate() { + let node = &dag.dag[*cancel_gate]; + if let NodeType::Operation(inst) = node { + if gate_eq(py, inst, &gate)? { + chunk.push(*cancel_gate); + } else { + if !chunk.is_empty() { + partitions.push(std::mem::take(&mut chunk)); + } + continue; + } + if i == max_index { + partitions.push(std::mem::take(&mut chunk)); + } else { + let next_qargs = if let NodeType::Operation(next_inst) = + &dag.dag[gate_cancel_run[i + 1]] + { + next_inst.qubits + } else { + panic!("Not an op node") + }; + if inst.qubits != next_qargs { + partitions.push(std::mem::take(&mut chunk)); + } + } + } else { + panic!("Not an op node"); + } + } + for chunk in partitions { + if chunk.len() % 2 == 0 { + dag.remove_op_node(chunk[0]); + } + for node in &chunk[1..] { + dag.remove_op_node(*node); + } + } + } + } + Ok(()) +} +fn run_on_inverse_pairs( + py: Python, + dag: &mut DAGCircuit, + op_counts: &IndexMap, + inverse_gate_names: HashSet, + inverse_gates: Vec<[OperationFromPython; 2]>, +) -> PyResult<()> { + if !inverse_gate_names + .iter() + .any(|name| op_counts.contains_key(name)) + { + return Ok(()); + } + for [gate_0, gate_1] in inverse_gates { + let gate_0_name = gate_0.operation.name(); + let gate_1_name = gate_1.operation.name(); + if !op_counts.contains_key(gate_0_name) || !op_counts.contains_key(gate_1_name) { + continue; + } + let names: HashSet = [&gate_0, &gate_1] + .iter() + .map(|x| x.operation.name().to_string()) + .collect(); + let runs: Vec> = dag.collect_runs(names).unwrap().collect(); + for nodes in runs { + let mut i = 0; + while i < nodes.len() - 1 { + if let NodeType::Operation(inst) = &dag.dag[nodes[i]] { + if let NodeType::Operation(next_inst) = &dag.dag[nodes[i + 1]] { + if inst.qubits == next_inst.qubits + && ((gate_eq(py, inst, &gate_0)? && gate_eq(py, next_inst, &gate_1)?) + || (gate_eq(py, inst, &gate_1)? + && gate_eq(py, next_inst, &gate_0)?)) + { + dag.remove_op_node(nodes[i]); + dag.remove_op_node(nodes[i + 1]); + i += 2; + } else { + i += 1; + } + } else { + panic!("Not an op node") + } + } else { + panic!("Not an op node") + } + } + } + } + Ok(()) +} + +#[pyfunction] +pub fn inverse_cancellation( + py: Python, + dag: &mut DAGCircuit, + inverse_gates: Vec<[OperationFromPython; 2]>, + self_inverse_gates: Vec, + inverse_gate_names: HashSet, + self_inverse_gate_names: HashSet, +) -> PyResult<()> { + if self_inverse_gate_names.is_empty() && inverse_gate_names.is_empty() { + return Ok(()); + } + let op_counts = dag.count_ops(py, true)?; + if !self_inverse_gate_names.is_empty() { + run_on_self_inverse( + py, + dag, + &op_counts, + self_inverse_gate_names, + self_inverse_gates, + )?; + } + if !inverse_gate_names.is_empty() { + run_on_inverse_pairs(py, dag, &op_counts, inverse_gate_names, inverse_gates)?; + } + Ok(()) +} + +pub fn inverse_cancellation_mod(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(inverse_cancellation))?; + Ok(()) +} diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index f11f28071e2c..26d93ab3f65e 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -24,6 +24,7 @@ pub mod edge_collections; pub mod error_map; pub mod euler_one_qubit_decomposer; pub mod filter_op_nodes; +pub mod inverse_cancellation; pub mod isometry; pub mod nlayout; pub mod optimize_1q_gates; diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 4d41660708d3..e57942f87cc0 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -4575,45 +4575,9 @@ def _format(operand): /// /// Returns: /// Mapping[str, int]: a mapping of operation names to the number of times it appears. - #[pyo3(signature = (*, recurse=true))] - fn count_ops(&self, py: Python, recurse: bool) -> PyResult { - if !recurse || !self.has_control_flow() { - Ok(self.op_names.to_object(py)) - } else { - fn inner( - py: Python, - dag: &DAGCircuit, - counts: &mut HashMap, - ) -> PyResult<()> { - for (key, value) in dag.op_names.iter() { - counts - .entry(key.clone()) - .and_modify(|count| *count += value) - .or_insert(*value); - } - let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); - for node in dag.dag.node_weights() { - let NodeType::Operation(node) = node else { - continue; - }; - if !node.op.control_flow() { - continue; - } - let OperationRef::Instruction(inst) = node.op.view() else { - panic!("control flow op must be an instruction") - }; - let blocks = inst.instruction.bind(py).getattr("blocks")?; - for block in blocks.iter()? { - let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block?,))?.extract()?; - inner(py, inner_dag, counts)?; - } - } - Ok(()) - } - let mut counts = HashMap::with_capacity(self.op_names.len()); - inner(py, self, &mut counts)?; - Ok(counts.to_object(py)) - } + #[pyo3(name = "count_ops", signature = (*, recurse=true))] + fn py_count_ops(&self, py: Python, recurse: bool) -> PyResult { + self.count_ops(py, recurse).map(|x| x.into_py(py)) } /// Count the occurrences of operation names on the longest path. @@ -4745,7 +4709,7 @@ def _format(operand): ("qubits", self.num_qubits().into_py(py)), ("bits", self.num_clbits().into_py(py)), ("factors", self.num_tensor_factors().into_py(py)), - ("operations", self.count_ops(py, true)?), + ("operations", self.py_count_ops(py, true)?), ])) } @@ -6365,6 +6329,56 @@ impl DAGCircuit { } } + /// Return the op name counts in the circuit + /// + /// Args: + /// py: The python token necessary for control flow recursion + /// recurse: Whether to recurse into control flow ops or not + pub fn count_ops( + &self, + py: Python, + recurse: bool, + ) -> PyResult> { + if !recurse || !self.has_control_flow() { + Ok(self.op_names.clone()) + } else { + fn inner( + py: Python, + dag: &DAGCircuit, + counts: &mut IndexMap, + ) -> PyResult<()> { + for (key, value) in dag.op_names.iter() { + counts + .entry(key.clone()) + .and_modify(|count| *count += value) + .or_insert(*value); + } + let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); + for node in dag.dag.node_weights() { + let NodeType::Operation(node) = node else { + continue; + }; + if !node.op.control_flow() { + continue; + } + let OperationRef::Instruction(inst) = node.op.view() else { + panic!("control flow op must be an instruction") + }; + let blocks = inst.instruction.bind(py).getattr("blocks")?; + for block in blocks.iter()? { + let inner_dag: &DAGCircuit = &circuit_to_dag.call1((block?,))?.extract()?; + inner(py, inner_dag, counts)?; + } + } + Ok(()) + } + let mut counts = + IndexMap::with_capacity_and_hasher(self.op_names.len(), RandomState::default()); + inner(py, self, &mut counts)?; + Ok(counts) + } + } + /// Extends the DAG with valid instances of [PackedInstruction] pub fn extend(&mut self, py: Python, iter: I) -> PyResult> where diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index ec883c69c3f1..331703809397 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -17,8 +17,9 @@ use qiskit_accelerate::{ commutation_analysis::commutation_analysis, commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, - filter_op_nodes::filter_op_nodes_mod, isometry::isometry, nlayout::nlayout, - optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, + filter_op_nodes::filter_op_nodes_mod, inverse_cancellation::inverse_cancellation_mod, + isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, + pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, @@ -48,6 +49,7 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, dense_layout, "dense_layout")?; add_submodule(m, error_map, "error_map")?; add_submodule(m, euler_one_qubit_decomposer, "euler_one_qubit_decomposer")?; + add_submodule(m, inverse_cancellation_mod, "inverse_cancellation")?; add_submodule(m, filter_op_nodes_mod, "filter_op_nodes")?; add_submodule(m, isometry, "isometry")?; add_submodule(m, nlayout, "nlayout")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 386b9cd082da..27830243d852 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -92,6 +92,7 @@ sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase +sys.modules["qiskit._accelerate.inverse_cancellation"] = _accelerate.inverse_cancellation sys.modules["qiskit._accelerate.check_map"] = _accelerate.check_map sys.modules["qiskit._accelerate.filter_op_nodes"] = _accelerate.filter_op_nodes diff --git a/qiskit/transpiler/passes/optimization/inverse_cancellation.py b/qiskit/transpiler/passes/optimization/inverse_cancellation.py index f5523432c26e..40876679e8d9 100644 --- a/qiskit/transpiler/passes/optimization/inverse_cancellation.py +++ b/qiskit/transpiler/passes/optimization/inverse_cancellation.py @@ -20,6 +20,8 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError +from qiskit._accelerate.inverse_cancellation import inverse_cancellation + class InverseCancellation(TransformationPass): """Cancel specific Gates which are inverses of each other when they occur back-to- @@ -81,96 +83,11 @@ def run(self, dag: DAGCircuit): Returns: DAGCircuit: Transformed DAG. """ - if self.self_inverse_gates: - dag = self._run_on_self_inverse(dag) - if self.inverse_gate_pairs: - dag = self._run_on_inverse_pairs(dag) - return dag - - def _run_on_self_inverse(self, dag: DAGCircuit): - """ - Run self-inverse gates on `dag`. - - Args: - dag: the directed acyclic graph to run on. - self_inverse_gates: list of gates who cancel themeselves in pairs - - Returns: - DAGCircuit: Transformed DAG. - """ - op_counts = dag.count_ops() - if not self.self_inverse_gate_names.intersection(op_counts): - return dag - # Sets of gate runs by name, for instance: [{(H 0, H 0), (H 1, H 1)}, {(X 0, X 0}] - for gate in self.self_inverse_gates: - gate_name = gate.name - gate_count = op_counts.get(gate_name, 0) - if gate_count <= 1: - continue - gate_runs = dag.collect_runs([gate_name]) - for gate_cancel_run in gate_runs: - partitions = [] - chunk = [] - max_index = len(gate_cancel_run) - 1 - for i, cancel_gate in enumerate(gate_cancel_run): - if cancel_gate.op == gate: - chunk.append(cancel_gate) - else: - if chunk: - partitions.append(chunk) - chunk = [] - continue - if i == max_index or cancel_gate.qargs != gate_cancel_run[i + 1].qargs: - partitions.append(chunk) - chunk = [] - # Remove an even number of gates from each chunk - for chunk in partitions: - if len(chunk) % 2 == 0: - dag.remove_op_node(chunk[0]) - for node in chunk[1:]: - dag.remove_op_node(node) - return dag - - def _run_on_inverse_pairs(self, dag: DAGCircuit): - """ - Run inverse gate pairs on `dag`. - - Args: - dag: the directed acyclic graph to run on. - inverse_gate_pairs: list of gates with inverse angles that cancel each other. - - Returns: - DAGCircuit: Transformed DAG. - """ - op_counts = dag.count_ops() - if not self.inverse_gate_pairs_names.intersection(op_counts): - return dag - - for pair in self.inverse_gate_pairs: - gate_0_name = pair[0].name - gate_1_name = pair[1].name - if gate_0_name not in op_counts or gate_1_name not in op_counts: - continue - gate_cancel_runs = dag.collect_runs([gate_0_name, gate_1_name]) - for dag_nodes in gate_cancel_runs: - i = 0 - while i < len(dag_nodes) - 1: - if ( - dag_nodes[i].qargs == dag_nodes[i + 1].qargs - and dag_nodes[i].op == pair[0] - and dag_nodes[i + 1].op == pair[1] - ): - dag.remove_op_node(dag_nodes[i]) - dag.remove_op_node(dag_nodes[i + 1]) - i = i + 2 - elif ( - dag_nodes[i].qargs == dag_nodes[i + 1].qargs - and dag_nodes[i].op == pair[1] - and dag_nodes[i + 1].op == pair[0] - ): - dag.remove_op_node(dag_nodes[i]) - dag.remove_op_node(dag_nodes[i + 1]) - i = i + 2 - else: - i = i + 1 + inverse_cancellation( + dag, + self.inverse_gate_pairs, + self.self_inverse_gates, + self.inverse_gate_pairs_names, + self.self_inverse_gate_names, + ) return dag From 734560e6c922afb88f2d4796e611e16a2d7923fa Mon Sep 17 00:00:00 2001 From: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:10:30 +0300 Subject: [PATCH 60/85] Oxidize CheckGateDirection (#13042) * First working implementation * A control flow fix, lint, doc and some more polishing * Addressing review comments and further simplifying the code * Address more review comments * Use explicit temp storage for mapping to avoid E0716 in Rust 1.70 * Allow checking 2Q non-control flow instructions --- crates/accelerate/src/gate_direction.rs | 150 ++++++++++++++++++ crates/accelerate/src/lib.rs | 1 + .../accelerate/src/target_transpiler/mod.rs | 2 +- crates/circuit/src/dag_circuit.rs | 30 ++-- crates/circuit/src/lib.rs | 2 +- crates/pyext/src/lib.rs | 7 +- qiskit/__init__.py | 1 + .../passes/utils/check_gate_direction.py | 49 +----- .../transpiler/test_check_gate_direction.py | 26 +-- 9 files changed, 196 insertions(+), 72 deletions(-) create mode 100644 crates/accelerate/src/gate_direction.rs diff --git a/crates/accelerate/src/gate_direction.rs b/crates/accelerate/src/gate_direction.rs new file mode 100644 index 000000000000..aee5ca097322 --- /dev/null +++ b/crates/accelerate/src/gate_direction.rs @@ -0,0 +1,150 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use crate::nlayout::PhysicalQubit; +use crate::target_transpiler::Target; +use hashbrown::HashSet; +use pyo3::prelude::*; +use qiskit_circuit::imports; +use qiskit_circuit::operations::OperationRef; +use qiskit_circuit::{ + dag_circuit::{DAGCircuit, NodeType}, + operations::Operation, + packed_instruction::PackedInstruction, + Qubit, +}; +use smallvec::smallvec; + +/// Check if the two-qubit gates follow the right direction with respect to the coupling map. +/// +/// Args: +/// dag: the DAGCircuit to analyze +/// +/// coupling_edges: set of edge pairs representing a directed coupling map, against which gate directionality is checked +/// +/// Returns: +/// true iff all two-qubit gates comply with the coupling constraints +#[pyfunction] +#[pyo3(name = "check_gate_direction_coupling")] +fn py_check_with_coupling_map( + py: Python, + dag: &DAGCircuit, + coupling_edges: HashSet<[Qubit; 2]>, +) -> PyResult { + let coupling_map_check = + |_: &PackedInstruction, op_args: &[Qubit]| -> bool { coupling_edges.contains(op_args) }; + + check_gate_direction(py, dag, &coupling_map_check, None) +} + +/// Check if the two-qubit gates follow the right direction with respect to instructions supported in the given target. +/// +/// Args: +/// dag: the DAGCircuit to analyze +/// +/// target: the Target against which gate directionality compliance is checked +/// +/// Returns: +/// true iff all two-qubit gates comply with the target's coupling constraints +#[pyfunction] +#[pyo3(name = "check_gate_direction_target")] +fn py_check_with_target(py: Python, dag: &DAGCircuit, target: &Target) -> PyResult { + let target_check = |inst: &PackedInstruction, op_args: &[Qubit]| -> bool { + let qargs = smallvec![ + PhysicalQubit::new(op_args[0].0), + PhysicalQubit::new(op_args[1].0) + ]; + + target.instruction_supported(inst.op.name(), Some(&qargs)) + }; + + check_gate_direction(py, dag, &target_check, None) +} + +// The main routine for checking gate directionality. +// +// gate_complies: a function returning true iff the two-qubit gate direction complies with directionality constraints +// +// qubit_mapping: used for mapping the index of a given qubit within an instruction qargs vector to the corresponding qubit index of the +// original DAGCircuit the pass was called with. This mapping is required since control flow blocks are represented by nested DAGCircuit +// objects whose instruction qubit indices are relative to the parent DAGCircuit they reside in, thus when we recurse into nested DAGs, we need +// to carry the mapping context relative to the original DAG. +// When qubit_mapping is None, the identity mapping is assumed +fn check_gate_direction( + py: Python, + dag: &DAGCircuit, + gate_complies: &T, + qubit_mapping: Option<&[Qubit]>, +) -> PyResult +where + T: Fn(&PackedInstruction, &[Qubit]) -> bool, +{ + for node in dag.op_nodes(false) { + let NodeType::Operation(packed_inst) = &dag.dag[node] else { + panic!("PackedInstruction is expected"); + }; + + let inst_qargs = dag.get_qargs(packed_inst.qubits); + + if let OperationRef::Instruction(py_inst) = packed_inst.op.view() { + if py_inst.control_flow() { + let circuit_to_dag = imports::CIRCUIT_TO_DAG.get_bound(py); // TODO: Take out of the recursion + let py_inst = py_inst.instruction.bind(py); + + for block in py_inst.getattr("blocks")?.iter()? { + let inner_dag: DAGCircuit = circuit_to_dag.call1((block?,))?.extract()?; + + let block_ok = if let Some(mapping) = qubit_mapping { + let mapping = inst_qargs // Create a temp mapping for the recursive call + .iter() + .map(|q| mapping[q.0 as usize]) + .collect::>(); + + check_gate_direction(py, &inner_dag, gate_complies, Some(&mapping))? + } else { + check_gate_direction(py, &inner_dag, gate_complies, Some(inst_qargs))? + }; + + if !block_ok { + return Ok(false); + } + } + continue; + } + } + + if inst_qargs.len() == 2 + && !match qubit_mapping { + // Check gate direction based either on a given custom mapping or the identity mapping + Some(mapping) => gate_complies( + packed_inst, + &[ + mapping[inst_qargs[0].0 as usize], + mapping[inst_qargs[1].0 as usize], + ], + ), + None => gate_complies(packed_inst, inst_qargs), + } + { + return Ok(false); + } + } + + Ok(true) +} + +#[pymodule] +pub fn gate_direction(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(py_check_with_coupling_map))?; + m.add_wrapped(wrap_pyfunction!(py_check_with_target))?; + Ok(()) +} diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 26d93ab3f65e..916aeeb8351c 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -24,6 +24,7 @@ pub mod edge_collections; pub mod error_map; pub mod euler_one_qubit_decomposer; pub mod filter_op_nodes; +pub mod gate_direction; pub mod inverse_cancellation; pub mod isometry; pub mod nlayout; diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index 08b3e90eabba..65fc8e80d750 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -50,7 +50,7 @@ mod exceptions { } // Custom types -type Qargs = SmallVec<[PhysicalQubit; 2]>; +pub type Qargs = SmallVec<[PhysicalQubit; 2]>; type GateMap = IndexMap; type PropsMap = NullableIndexMap>; type GateMapState = Vec<(String, Vec<(Option, Option)>)>; diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index e57942f87cc0..5b9769b4d19e 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -3975,19 +3975,12 @@ def _format(operand): } /// Get list of 2 qubit operations. Ignore directives like snapshot and barrier. - fn two_qubit_ops(&self, py: Python) -> PyResult>> { + #[pyo3(name = "two_qubit_ops")] + pub fn py_two_qubit_ops(&self, py: Python) -> PyResult>> { let mut nodes = Vec::new(); - for (node, weight) in self.dag.node_references() { - if let NodeType::Operation(ref packed) = weight { - if packed.op.directive() { - continue; - } - - let qargs = self.qargs_interner.get(packed.qubits); - if qargs.len() == 2 { - nodes.push(self.unpack_into(py, node, weight)?); - } - } + for node in self.two_qubit_ops() { + let weight = self.dag.node_weight(node).expect("NodeIndex in graph"); + nodes.push(self.unpack_into(py, node, weight)?); } Ok(nodes) } @@ -5756,6 +5749,19 @@ impl DAGCircuit { } } + /// Return an iterator of 2 qubit operations. Ignore directives like snapshot and barrier. + pub fn two_qubit_ops(&self) -> impl Iterator + '_ { + Box::new(self.op_nodes(false).filter(|index| { + let weight = self.dag.node_weight(*index).expect("NodeIndex in graph"); + if let NodeType::Operation(ref packed) = weight { + let qargs = self.qargs_interner.get(packed.qubits); + qargs.len() == 2 + } else { + false + } + })) + } + // Filter any nodes that don't match a given predicate function pub fn filter_op_nodes(&mut self, mut predicate: F) where diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index 4ca86c2ca83c..5106ba030288 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -32,7 +32,7 @@ use pyo3::prelude::*; use pyo3::types::{PySequence, PyTuple}; pub type BitType = u32; -#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, FromPyObject)] pub struct Qubit(pub BitType); #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] pub struct Clbit(pub BitType); diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 331703809397..96b5e84a9cbe 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -17,9 +17,9 @@ use qiskit_accelerate::{ commutation_analysis::commutation_analysis, commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, - filter_op_nodes::filter_op_nodes_mod, inverse_cancellation::inverse_cancellation_mod, - isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, - pauli_exp_val::pauli_expval, + filter_op_nodes::filter_op_nodes_mod, gate_direction::gate_direction, + inverse_cancellation::inverse_cancellation_mod, isometry::isometry, nlayout::nlayout, + optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, @@ -72,6 +72,7 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, uc_gate, "uc_gate")?; add_submodule(m, utils, "utils")?; add_submodule(m, vf2_layout, "vf2_layout")?; + add_submodule(m, gate_direction, "gate_direction")?; add_submodule(m, commutation_checker, "commutation_checker")?; add_submodule(m, commutation_analysis, "commutation_analysis")?; Ok(()) diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 27830243d852..f731465beecb 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -92,6 +92,7 @@ sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase +sys.modules["qiskit._accelerate.gate_direction"] = _accelerate.gate_direction sys.modules["qiskit._accelerate.inverse_cancellation"] = _accelerate.inverse_cancellation sys.modules["qiskit._accelerate.check_map"] = _accelerate.check_map sys.modules["qiskit._accelerate.filter_op_nodes"] = _accelerate.filter_op_nodes diff --git a/qiskit/transpiler/passes/utils/check_gate_direction.py b/qiskit/transpiler/passes/utils/check_gate_direction.py index e797be95c4a1..5251bfc8de96 100644 --- a/qiskit/transpiler/passes/utils/check_gate_direction.py +++ b/qiskit/transpiler/passes/utils/check_gate_direction.py @@ -12,9 +12,11 @@ """Check if the gates follow the right direction with respect to the coupling map.""" -from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES -from qiskit.converters import circuit_to_dag from qiskit.transpiler.basepasses import AnalysisPass +from qiskit._accelerate.gate_direction import ( + check_gate_direction_coupling, + check_gate_direction_target, +) class CheckGateDirection(AnalysisPass): @@ -34,42 +36,6 @@ def __init__(self, coupling_map, target=None): self.coupling_map = coupling_map self.target = target - def _coupling_map_visit(self, dag, wire_map, edges=None): - if edges is None: - edges = self.coupling_map.get_edges() - # Don't include directives to avoid things like barrier, which are assumed always supported. - for node in dag.op_nodes(include_directives=False): - if node.name in CONTROL_FLOW_OP_NAMES: - for block in node.op.blocks: - inner_wire_map = { - inner: wire_map[outer] for outer, inner in zip(node.qargs, block.qubits) - } - - if not self._coupling_map_visit(circuit_to_dag(block), inner_wire_map, edges): - return False - elif ( - len(node.qargs) == 2 - and (wire_map[node.qargs[0]], wire_map[node.qargs[1]]) not in edges - ): - return False - return True - - def _target_visit(self, dag, wire_map): - # Don't include directives to avoid things like barrier, which are assumed always supported. - for node in dag.op_nodes(include_directives=False): - if node.name in CONTROL_FLOW_OP_NAMES: - for block in node.op.blocks: - inner_wire_map = { - inner: wire_map[outer] for outer, inner in zip(node.qargs, block.qubits) - } - if not self._target_visit(circuit_to_dag(block), inner_wire_map): - return False - elif len(node.qargs) == 2 and not self.target.instruction_supported( - node.name, (wire_map[node.qargs[0]], wire_map[node.qargs[1]]) - ): - return False - return True - def run(self, dag): """Run the CheckGateDirection pass on `dag`. @@ -79,9 +45,8 @@ def run(self, dag): Args: dag (DAGCircuit): DAG to check. """ - wire_map = {bit: i for i, bit in enumerate(dag.qubits)} self.property_set["is_direction_mapped"] = ( - self._coupling_map_visit(dag, wire_map) - if self.target is None - else self._target_visit(dag, wire_map) + check_gate_direction_target(dag, self.target) + if self.target + else check_gate_direction_coupling(dag, set(self.coupling_map.get_edges())) ) diff --git a/test/python/transpiler/test_check_gate_direction.py b/test/python/transpiler/test_check_gate_direction.py index 0743f4c04cfc..efd38af16634 100644 --- a/test/python/transpiler/test_check_gate_direction.py +++ b/test/python/transpiler/test_check_gate_direction.py @@ -72,13 +72,13 @@ def test_true_direction(self): def test_true_direction_in_same_layer(self): """Two CXs distance_qubits 1 to each other, in the same layer - qr0:--(+)-- + qr0:---.-- | - qr1:---.--- + qr1:--(+)--- - qr2:--(+)-- + qr2:---.--- | - qr3:---.--- + qr3:--(+)-- CouplingMap map: [0]->[1]->[2]->[3] """ @@ -96,9 +96,9 @@ def test_true_direction_in_same_layer(self): def test_wrongly_mapped(self): """Needs [0]-[1] in a [0]--[2]--[1] - qr0:--(+)-- + qr0:---.--- | - qr1:---.--- + qr1:--(+)-- CouplingMap map: [0]->[2]->[1] """ @@ -115,11 +115,11 @@ def test_wrongly_mapped(self): def test_true_direction_undirected(self): """Mapped but with wrong direction - qr0:--(+)-[H]--.-- + qr0:---.--[H]-(+)- | | - qr1:---.-------|-- + qr1:--(+)------|-- | - qr2:----------(+)- + qr2:-----------.-- CouplingMap map: [1]<-[0]->[2] """ @@ -138,13 +138,13 @@ def test_true_direction_undirected(self): def test_false_direction_in_same_layer_undirected(self): """Two CXs in the same layer, but one is wrongly directed - qr0:--(+)-- + qr0:---.--- | - qr1:---.--- + qr1:--(+)-- - qr2:---.--- + qr2:--(+)-- | - qr3:--(+)-- + qr3:---.--- CouplingMap map: [0]->[1]->[2]->[3] """ From 3aa58cc2ab8bc0c4e600dbfe9c01c6ce4872ec0d Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Mon, 9 Sep 2024 09:49:41 +0100 Subject: [PATCH 61/85] Add equivalence-library rules between `rzz` and `cp` (#13019) * Add equivalence-library rules between `rzz` and `cp` These gates are locally equivalence (as are all the Ising-interaction gates), and this simple additional rule lets things like QFT, which are defined by Qiskit's default constructor in terms of `cp`, get converted into `rzz` or `rzx`. One `ControlledGate` test needed a case removing, because the underlying control mechanism now works correctly. * Rewrite release note --- .../standard_gates/equivalence_library.py | 43 +++++++++++++++++++ ...hase-rzz-equivalence-e8afc37b71a74366.yaml | 17 ++++++++ test/python/circuit/test_controlled_gate.py | 1 - 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index c4619ca27858..93e772ff842d 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -189,6 +189,21 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True): cphase_to_cu1.append(CU1Gate(theta), [0, 1]) _sel.add_equivalence(CPhaseGate(theta), cphase_to_cu1) +# CPhaseGate +# +# global phase: ϴ/4 +# ┌─────────┐ +# q_0: ─■──── q_0: ─■─────────┤ Rz(ϴ/2) ├ +# │P(ϴ) ≡ │ZZ(-ϴ/2) ├─────────┤ +# q_1: ─■──── q_1: ─■─────────┤ Rz(ϴ/2) ├ +# └─────────┘ +theta = Parameter("theta") +cphase_to_rzz = QuantumCircuit(2, global_phase=theta / 4) +cphase_to_rzz.rzz(-theta / 2, 0, 1) +cphase_to_rzz.rz(theta / 2, 0) +cphase_to_rzz.rz(theta / 2, 1) +_sel.add_equivalence(CPhaseGate(theta), cphase_to_rzz) + # RGate # # ┌────────┐ ┌───────────────────────┐ @@ -394,6 +409,19 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True): def_rzx.append(inst, qargs, cargs) _sel.add_equivalence(RZXGate(theta), def_rzx) +# RZXGate to RZZGate +# ┌─────────┐ +# q_0: ┤0 ├ q_0: ──────■─────────── +# │ Rzx(ϴ) │ ≡ ┌───┐ │ZZ(ϴ) ┌───┐ +# q_1: ┤1 ├ q_1: ┤ H ├─■──────┤ H ├ +# └─────────┘ └───┘ └───┘ +theta = Parameter("theta") +rzx_to_rzz = QuantumCircuit(2) +rzx_to_rzz.h(1) +rzx_to_rzz.rzz(theta, 0, 1) +rzx_to_rzz.h(1) +_sel.add_equivalence(RZXGate(theta), rzx_to_rzz) + # RYGate # @@ -654,6 +682,21 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True): rzz_to_rzx.h(1) _sel.add_equivalence(RZZGate(theta), rzz_to_rzx) +# RZZ to CPhase +# +# global phase: ϴ/2 +# ┌───────┐ +# q_0: ─■───── q_0: ─■────────┤ Rz(ϴ) ├ +# │ZZ(ϴ) ≡ │P(-2*ϴ) ├───────┤ +# q_1: ─■───── q_1: ─■────────┤ Rz(ϴ) ├ +# └───────┘ +theta = Parameter("theta") +rzz_to_cphase = QuantumCircuit(2, global_phase=theta / 2) +rzz_to_cphase.cp(-theta * 2, 0, 1) +rzz_to_cphase.rz(theta, 0) +rzz_to_cphase.rz(theta, 1) +_sel.add_equivalence(RZZGate(theta), rzz_to_cphase) + # RZZ to RYY q = QuantumRegister(2, "q") theta = Parameter("theta") diff --git a/releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml b/releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml new file mode 100644 index 000000000000..9f4d9d384172 --- /dev/null +++ b/releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml @@ -0,0 +1,17 @@ +--- +features_circuits: + - | + The standard equivalence library (:data:`.SessionEquivalenceLibrary`) now has rules that can + directly convert between Qiskit's standard-library 2q continuous Ising-type interactions (e.g. + :class:`.CPhaseGate`, :class:`.RZZGate`, :class:`.RZXGate`, and so on) using local equivalence + relations. Previously, several of these conversions would go via a 2-CX form, which resulted + in less efficient circuit generation. + + .. note:: + + In general, the :class:`.BasisTranslator` is not guaranteed to find the "best" equivalence + relation for a given :class:`.Target`, but will always find an equivalence if one exists. We + rely on more expensive resynthesis and gate-optimization passes in the transpiler to improve + the output. These passes are currently not as effective for basis sets with a continuously + parametrized two-qubit interaction as they are for discrete super-controlled two-qubit + interactions. diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a517d5d1e4a4..03a041355b87 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -1438,7 +1438,6 @@ def test_control_zero_operand_gate(self, num_ctrl_qubits): @data( RXGate, RYGate, - RZGate, RXXGate, RYYGate, RZXGate, From 2ef371ae0d159a6dfd643805f3e5e5fdec37ab88 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 9 Sep 2024 09:09:24 -0400 Subject: [PATCH 62/85] Fully port Split2QUnitaries to rust (#13025) * Fully port Split2QUnitaries to rust This commit builds off of #13013 and the other data model in Rust infrastructure and migrates the InverseCancellation pass to operate fully in Rust. The full path of the transpiler pass now never leaves Rust until it has finished modifying the DAGCircuit. There is still some python interaction necessary to handle parts of the data model that are still in Python, mainly for creating `UnitaryGate` instances and `ParameterExpression` for global phase. But otherwise the entirety of the pass operates in rust now. This is just a first pass at the migration here, it moves the pass to use loops in rust. The next steps here are to look at operating the pass in parallel. There is no data dependency between the optimizations being done for different gates so we should be able to increase the throughput of the pass by leveraging multithreading to handle each gate in parallel. This commit does not attempt this though, because of the Python dependency and also the data structures around gates and the dag aren't really setup for multithreading yet and there likely will need to be some work to support that. Part of #12208 * Update pass logic with changes from #13095 Some of the logic inside the Split2QUnitaries pass was updated in a recently merged PR. This commit makes those changes so the rust implementation matches the current state of the previous python version. * Use op_nodes() instead of topological_op_nodes() * Use Fn trait instead of FnMut for callback We don't need the callback to be mutable currently so relax the trait to just be `Fn` instead of `FnMut`. If we have a need for a mutable environment callback in the future we can change this easily enough without any issues. * Avoid extra edge operations in replace_on_incoming_qubits * Rename function --- crates/accelerate/src/lib.rs | 1 + crates/accelerate/src/split_2q_unitaries.rs | 75 +++++++++++++++++++ crates/accelerate/src/two_qubit_decompose.rs | 12 +-- crates/circuit/src/dag_circuit.rs | 71 +++++++++++++++++- crates/circuit/src/imports.rs | 4 + crates/pyext/src/lib.rs | 8 +- qiskit/__init__.py | 1 + .../passes/optimization/split_2q_unitaries.py | 44 +---------- 8 files changed, 164 insertions(+), 52 deletions(-) create mode 100644 crates/accelerate/src/split_2q_unitaries.rs diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 916aeeb8351c..9e391e0a9030 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -35,6 +35,7 @@ pub mod results; pub mod sabre; pub mod sampled_exp_val; pub mod sparse_pauli_op; +pub mod split_2q_unitaries; pub mod star_prerouting; pub mod stochastic_swap; pub mod synthesis; diff --git a/crates/accelerate/src/split_2q_unitaries.rs b/crates/accelerate/src/split_2q_unitaries.rs new file mode 100644 index 000000000000..83ab94bf301d --- /dev/null +++ b/crates/accelerate/src/split_2q_unitaries.rs @@ -0,0 +1,75 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use pyo3::prelude::*; +use rustworkx_core::petgraph::stable_graph::NodeIndex; + +use qiskit_circuit::circuit_instruction::OperationFromPython; +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType, Wire}; +use qiskit_circuit::imports::UNITARY_GATE; +use qiskit_circuit::operations::{Operation, Param}; + +use crate::two_qubit_decompose::{Specialization, TwoQubitWeylDecomposition}; + +#[pyfunction] +pub fn split_2q_unitaries( + py: Python, + dag: &mut DAGCircuit, + requested_fidelity: f64, +) -> PyResult<()> { + let nodes: Vec = dag.op_nodes(false).collect(); + for node in nodes { + if let NodeType::Operation(inst) = &dag.dag[node] { + let qubits = dag.get_qargs(inst.qubits).to_vec(); + let matrix = inst.op.matrix(inst.params_view()); + // We only attempt to split UnitaryGate objects, but this could be extended in future + // -- however we need to ensure that we can compile the resulting single-qubit unitaries + // to the supported basis gate set. + if qubits.len() != 2 || inst.op.name() != "unitary" { + continue; + } + let decomp = TwoQubitWeylDecomposition::new_inner( + matrix.unwrap().view(), + Some(requested_fidelity), + None, + )?; + if matches!(decomp.specialization, Specialization::IdEquiv) { + let k1r_arr = decomp.K1r(py); + let k1l_arr = decomp.K1l(py); + let k1r_gate = UNITARY_GATE.get_bound(py).call1((k1r_arr,))?; + let k1l_gate = UNITARY_GATE.get_bound(py).call1((k1l_arr,))?; + let insert_fn = |edge: &Wire| -> PyResult { + if let Wire::Qubit(qubit) = edge { + if *qubit == qubits[0] { + k1r_gate.extract() + } else { + k1l_gate.extract() + } + } else { + unreachable!("This will only be called on ops with no classical wires."); + } + }; + dag.replace_node_with_1q_ops(py, node, insert_fn)?; + dag.add_global_phase(py, &Param::Float(decomp.global_phase))?; + } + // TODO: also look into splitting on Specialization::Swap and just + // swap the virtual qubits. Doing this we will need to update the + // permutation like in ElidePermutations + } + } + Ok(()) +} + +pub fn split_2q_unitaries_mod(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(split_2q_unitaries))?; + Ok(()) +} diff --git a/crates/accelerate/src/two_qubit_decompose.rs b/crates/accelerate/src/two_qubit_decompose.rs index 2c745b199e9e..92ad4724682f 100644 --- a/crates/accelerate/src/two_qubit_decompose.rs +++ b/crates/accelerate/src/two_qubit_decompose.rs @@ -341,7 +341,7 @@ const DEFAULT_FIDELITY: f64 = 1.0 - 1.0e-9; #[derive(Clone, Debug, Copy)] #[pyclass(module = "qiskit._accelerate.two_qubit_decompose")] -enum Specialization { +pub enum Specialization { General, IdEquiv, SWAPEquiv, @@ -410,13 +410,13 @@ pub struct TwoQubitWeylDecomposition { #[pyo3(get)] c: f64, #[pyo3(get)] - global_phase: f64, + pub global_phase: f64, K1l: Array2, K2l: Array2, K1r: Array2, K2r: Array2, #[pyo3(get)] - specialization: Specialization, + pub specialization: Specialization, default_euler_basis: EulerBasis, #[pyo3(get)] requested_fidelity: Option, @@ -476,7 +476,7 @@ impl TwoQubitWeylDecomposition { /// Instantiate a new TwoQubitWeylDecomposition with rust native /// data structures - fn new_inner( + pub fn new_inner( unitary_matrix: ArrayView2, fidelity: Option, @@ -1021,13 +1021,13 @@ impl TwoQubitWeylDecomposition { #[allow(non_snake_case)] #[getter] - fn K1l(&self, py: Python) -> PyObject { + pub fn K1l(&self, py: Python) -> PyObject { self.K1l.to_pyarray_bound(py).into() } #[allow(non_snake_case)] #[getter] - fn K1r(&self, py: Python) -> PyObject { + pub fn K1r(&self, py: Python) -> PyObject { self.K1r.to_pyarray_bound(py).into() } diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 5b9769b4d19e..0b5a43c1eb4b 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -5254,7 +5254,7 @@ impl DAGCircuit { Ok(nodes.into_iter()) } - fn topological_op_nodes(&self) -> PyResult + '_> { + pub fn topological_op_nodes(&self) -> PyResult + '_> { Ok(self.topological_nodes()?.filter(|node: &NodeIndex| { matches!(self.dag.node_weight(*node), Some(NodeType::Operation(_))) })) @@ -6285,6 +6285,75 @@ impl DAGCircuit { } } + /// Replace a node with individual operations from a provided callback + /// function on each qubit of that node. + #[allow(unused_variables)] + pub fn replace_node_with_1q_ops( + &mut self, + py: Python, // Unused if cache_pygates isn't enabled + node: NodeIndex, + insert: F, + ) -> PyResult<()> + where + F: Fn(&Wire) -> PyResult, + { + let mut edge_list: Vec<(NodeIndex, NodeIndex, Wire)> = Vec::with_capacity(2); + for (source, in_weight) in self + .dag + .edges_directed(node, Incoming) + .map(|x| (x.source(), x.weight())) + { + for (target, out_weight) in self + .dag + .edges_directed(node, Outgoing) + .map(|x| (x.target(), x.weight())) + { + if in_weight == out_weight { + edge_list.push((source, target, in_weight.clone())); + } + } + } + for (source, target, weight) in edge_list { + let new_op = insert(&weight)?; + self.increment_op(new_op.operation.name()); + let qubits = if let Wire::Qubit(qubit) = weight { + vec![qubit] + } else { + panic!("This method only works if the gate being replaced has no classical incident wires") + }; + #[cfg(feature = "cache_pygates")] + let py_op = match new_op.operation.view() { + OperationRef::Standard(_) => OnceCell::new(), + OperationRef::Gate(gate) => OnceCell::from(gate.gate.clone_ref(py)), + OperationRef::Instruction(instruction) => { + OnceCell::from(instruction.instruction.clone_ref(py)) + } + OperationRef::Operation(op) => OnceCell::from(op.operation.clone_ref(py)), + }; + let inst = PackedInstruction { + op: new_op.operation, + qubits: self.qargs_interner.insert_owned(qubits), + clbits: self.cargs_interner.get_default(), + params: (!new_op.params.is_empty()).then(|| Box::new(new_op.params)), + extra_attrs: new_op.extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op: py_op, + }; + let new_index = self.dag.add_node(NodeType::Operation(inst)); + self.dag.add_edge(source, new_index, weight.clone()); + self.dag.add_edge(new_index, target, weight); + } + + match self.dag.remove_node(node) { + Some(NodeType::Operation(packed)) => { + let op_name = packed.op.name(); + self.decrement_op(op_name); + } + _ => panic!("Must be called with valid operation node"), + } + Ok(()) + } + pub fn add_global_phase(&mut self, py: Python, value: &Param) -> PyResult<()> { match value { Param::Obj(_) => { diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index 588471546273..a8f6d9562559 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -109,6 +109,10 @@ pub static SWITCH_CASE_OP_CHECK: ImportOnceCell = pub static FOR_LOOP_OP_CHECK: ImportOnceCell = ImportOnceCell::new("qiskit.dagcircuit.dagnode", "_for_loop_eq"); pub static UUID: ImportOnceCell = ImportOnceCell::new("uuid", "UUID"); +pub static UNITARY_GATE: ImportOnceCell = ImportOnceCell::new( + "qiskit.circuit.library.generalized_gates.unitary", + "UnitaryGate", +); /// A mapping from the enum variant in crate::operations::StandardGate to the python /// module path and class name to import it. This is used to populate the conversion table diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 96b5e84a9cbe..03bd0202dae4 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -22,9 +22,10 @@ use qiskit_accelerate::{ optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, - star_prerouting::star_prerouting, stochastic_swap::stochastic_swap, synthesis::synthesis, - target_transpiler::target, two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, - utils::utils, vf2_layout::vf2_layout, + split_2q_unitaries::split_2q_unitaries_mod, star_prerouting::star_prerouting, + stochastic_swap::stochastic_swap, synthesis::synthesis, target_transpiler::target, + two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, utils::utils, + vf2_layout::vf2_layout, }; #[inline(always)] @@ -65,6 +66,7 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, sabre, "sabre")?; add_submodule(m, sampled_exp_val, "sampled_exp_val")?; add_submodule(m, sparse_pauli_op, "sparse_pauli_op")?; + add_submodule(m, split_2q_unitaries_mod, "split_2q_unitaries")?; add_submodule(m, star_prerouting, "star_prerouting")?; add_submodule(m, stochastic_swap, "stochastic_swap")?; add_submodule(m, target, "target")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index f731465beecb..29e2b8ba5c11 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -92,6 +92,7 @@ sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase +sys.modules["qiskit._accelerate.split_2q_unitaries"] = _accelerate.split_2q_unitaries sys.modules["qiskit._accelerate.gate_direction"] = _accelerate.gate_direction sys.modules["qiskit._accelerate.inverse_cancellation"] = _accelerate.inverse_cancellation sys.modules["qiskit._accelerate.check_map"] = _accelerate.check_map diff --git a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py index 1ca53c6c31d2..f6958a00a4c1 100644 --- a/qiskit/transpiler/passes/optimization/split_2q_unitaries.py +++ b/qiskit/transpiler/passes/optimization/split_2q_unitaries.py @@ -13,11 +13,8 @@ """Splits each two-qubit gate in the `dag` into two single-qubit gates, if possible without error.""" from qiskit.transpiler.basepasses import TransformationPass -from qiskit.circuit.quantumcircuitdata import CircuitInstruction from qiskit.dagcircuit.dagcircuit import DAGCircuit -from qiskit.dagcircuit.dagnode import DAGOpNode -from qiskit.circuit.library.generalized_gates import UnitaryGate -from qiskit.synthesis.two_qubit.two_qubit_decompose import TwoQubitWeylDecomposition +from qiskit._accelerate.split_2q_unitaries import split_2q_unitaries class Split2QUnitaries(TransformationPass): @@ -39,42 +36,5 @@ def __init__(self, fidelity: float = 1.0 - 1e-16): def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Split2QUnitaries pass on `dag`.""" - - for node in dag.topological_op_nodes(): - # We only attempt to split UnitaryGate objects, but this could be extended in future - # -- however we need to ensure that we can compile the resulting single-qubit unitaries - # to the supported basis gate set. - if not (len(node.qargs) == 2 and node.op.name == "unitary"): - continue - - decomp = TwoQubitWeylDecomposition(node.matrix, fidelity=self.requested_fidelity) - if ( - decomp._inner_decomposition.specialization - == TwoQubitWeylDecomposition._specializations.IdEquiv - ): - new_dag = DAGCircuit() - new_dag.add_qubits(node.qargs) - - ur = decomp.K1r - ur_node = DAGOpNode.from_instruction( - CircuitInstruction(UnitaryGate(ur), qubits=(node.qargs[0],)) - ) - - ul = decomp.K1l - ul_node = DAGOpNode.from_instruction( - CircuitInstruction(UnitaryGate(ul), qubits=(node.qargs[1],)) - ) - new_dag._apply_op_node_back(ur_node) - new_dag._apply_op_node_back(ul_node) - new_dag.global_phase = decomp.global_phase - dag.substitute_node_with_dag(node, new_dag) - elif ( - decomp._inner_decomposition.specialization - == TwoQubitWeylDecomposition._specializations.SWAPEquiv - ): - # TODO maybe also look into swap-gate-like gates? Things to consider: - # * As the qubit mapping may change, we'll always need to build a new dag in this pass - # * There may not be many swap-gate-like gates in an arbitrary input circuit - # * Removing swap gates from a user-routed input circuit here is unexpected - pass + split_2q_unitaries(dag, self.requested_fidelity) return dag From d14eb9c4829268cd531c4a6ff68f5a297dc84b3c Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 10 Sep 2024 16:10:24 +0200 Subject: [PATCH 63/85] Fix skipping of slow tests (#13119) --- test/utils/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/decorators.py b/test/utils/decorators.py index d3abb37bbef1..1b1df0efc9c1 100644 --- a/test/utils/decorators.py +++ b/test/utils/decorators.py @@ -33,7 +33,7 @@ def slow_test(func): @functools.wraps(func) def _wrapper(*args, **kwargs): - if "run_slow" in os.environ.get("QISKIT_TESTS", ""): + if "run_slow" not in os.environ.get("QISKIT_TESTS", ""): raise unittest.SkipTest("Skipping slow tests") return func(*args, **kwargs) From 1962704cf120499cee5f017eb21d3e217353c4d7 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 10 Sep 2024 16:22:33 +0200 Subject: [PATCH 64/85] Fix creation of registers in synthesis methods (#13086) * add qregs to output circuits * never develop while not on up-to-date main * one shan't commit faster than ones IDE can run black * avoid compose --- qiskit/circuit/quantumcircuit.py | 53 ++++++++++++++----- .../clifford/clifford_decompose_bm.py | 2 +- .../clifford/clifford_decompose_greedy.py | 2 +- qiskit/synthesis/linear/cnot_synth.py | 2 +- qiskit/synthesis/linear_phase/cz_depth_lnn.py | 4 +- .../one_qubit/one_qubit_decompose.py | 3 +- .../synthesis/permutation/permutation_full.py | 4 +- .../synthesis/permutation/permutation_lnn.py | 4 +- .../permutation/permutation_reverse_lnn.py | 4 +- .../two_qubit/two_qubit_decompose.py | 4 +- .../fix-synth-qregs-7662681c0ff02511.yaml | 7 +++ .../operators/symplectic/test_clifford.py | 17 ++++++ 12 files changed, 81 insertions(+), 25 deletions(-) create mode 100644 releasenotes/notes/fix-synth-qregs-7662681c0ff02511.yaml diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index ebc63511ca7b..566a6fef9f70 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -1152,17 +1152,41 @@ def __init__( """The unit that :attr:`duration` is specified in.""" self.metadata = {} if metadata is None else metadata """Arbitrary user-defined metadata for the circuit. - + Qiskit will not examine the content of this mapping, but it will pass it through the transpiler and reattach it to the output, so you can track your own metadata.""" @classmethod - def _from_circuit_data(cls, data: CircuitData) -> typing.Self: + def _from_circuit_data(cls, data: CircuitData, add_regs: bool = False) -> typing.Self: """A private constructor from rust space circuit data.""" out = QuantumCircuit() + + if data.num_qubits > 0: + if add_regs: + qr = QuantumRegister(name="q", bits=data.qubits) + out.qregs = [qr] + out._qubit_indices = { + bit: BitLocations(index, [(qr, index)]) for index, bit in enumerate(data.qubits) + } + else: + out._qubit_indices = { + bit: BitLocations(index, []) for index, bit in enumerate(data.qubits) + } + + if data.num_clbits > 0: + if add_regs: + cr = ClassicalRegister(name="c", bits=data.clbits) + out.cregs = [cr] + out._clbit_indices = { + bit: BitLocations(index, [(cr, index)]) for index, bit in enumerate(data.clbits) + } + else: + out._clbit_indices = { + bit: BitLocations(index, []) for index, bit in enumerate(data.clbits) + } + out._data = data - out._qubit_indices = {bit: BitLocations(index, []) for index, bit in enumerate(data.qubits)} - out._clbit_indices = {bit: BitLocations(index, []) for index, bit in enumerate(data.clbits)} + return out @staticmethod @@ -3013,16 +3037,7 @@ def add_register(self, *regs: Register | int | Sequence[Bit]) -> None: self._ancillas.append(bit) if isinstance(register, QuantumRegister): - self.qregs.append(register) - - for idx, bit in enumerate(register): - if bit in self._qubit_indices: - self._qubit_indices[bit].registers.append((register, idx)) - else: - self._data.add_qubit(bit) - self._qubit_indices[bit] = BitLocations( - self._data.num_qubits - 1, [(register, idx)] - ) + self._add_qreg(register) elif isinstance(register, ClassicalRegister): self.cregs.append(register) @@ -3041,6 +3056,16 @@ def add_register(self, *regs: Register | int | Sequence[Bit]) -> None: else: raise CircuitError("expected a register") + def _add_qreg(self, qreg: QuantumRegister) -> None: + self.qregs.append(qreg) + + for idx, bit in enumerate(qreg): + if bit in self._qubit_indices: + self._qubit_indices[bit].registers.append((qreg, idx)) + else: + self._data.add_qubit(bit) + self._qubit_indices[bit] = BitLocations(self._data.num_qubits - 1, [(qreg, idx)]) + def add_bits(self, bits: Iterable[Bit]) -> None: """Add Bits to the circuit.""" duplicate_bits = { diff --git a/qiskit/synthesis/clifford/clifford_decompose_bm.py b/qiskit/synthesis/clifford/clifford_decompose_bm.py index ac4923446bcd..5ead6945eba2 100644 --- a/qiskit/synthesis/clifford/clifford_decompose_bm.py +++ b/qiskit/synthesis/clifford/clifford_decompose_bm.py @@ -41,7 +41,7 @@ def synth_clifford_bm(clifford: Clifford) -> QuantumCircuit: `arXiv:2003.09412 [quant-ph] `_ """ circuit = QuantumCircuit._from_circuit_data( - synth_clifford_bm_inner(clifford.tableau.astype(bool)) + synth_clifford_bm_inner(clifford.tableau.astype(bool)), add_regs=True ) circuit.name = str(clifford) return circuit diff --git a/qiskit/synthesis/clifford/clifford_decompose_greedy.py b/qiskit/synthesis/clifford/clifford_decompose_greedy.py index 0a679a8a7a6f..9766efe4aa8f 100644 --- a/qiskit/synthesis/clifford/clifford_decompose_greedy.py +++ b/qiskit/synthesis/clifford/clifford_decompose_greedy.py @@ -51,7 +51,7 @@ def synth_clifford_greedy(clifford: Clifford) -> QuantumCircuit: `arXiv:2105.02291 [quant-ph] `_ """ circuit = QuantumCircuit._from_circuit_data( - synth_clifford_greedy_inner(clifford.tableau.astype(bool)) + synth_clifford_greedy_inner(clifford.tableau.astype(bool)), add_regs=True ) circuit.name = str(clifford) return circuit diff --git a/qiskit/synthesis/linear/cnot_synth.py b/qiskit/synthesis/linear/cnot_synth.py index f900ff86d17e..bb3d9c6896ff 100644 --- a/qiskit/synthesis/linear/cnot_synth.py +++ b/qiskit/synthesis/linear/cnot_synth.py @@ -66,4 +66,4 @@ def synth_cnot_count_full_pmh( circuit_data = fast_pmh(normalized, section_size) # construct circuit from the data - return QuantumCircuit._from_circuit_data(circuit_data) + return QuantumCircuit._from_circuit_data(circuit_data, add_regs=True) diff --git a/qiskit/synthesis/linear_phase/cz_depth_lnn.py b/qiskit/synthesis/linear_phase/cz_depth_lnn.py index 419aec806f2e..d7dd071956e0 100644 --- a/qiskit/synthesis/linear_phase/cz_depth_lnn.py +++ b/qiskit/synthesis/linear_phase/cz_depth_lnn.py @@ -53,4 +53,6 @@ def synth_cz_depth_line_mr(mat: np.ndarray) -> QuantumCircuit: """ # Call Rust implementaton - return QuantumCircuit._from_circuit_data(synth_cz_depth_line_mr_inner(mat.astype(bool))) + return QuantumCircuit._from_circuit_data( + synth_cz_depth_line_mr_inner(mat.astype(bool)), add_regs=True + ) diff --git a/qiskit/synthesis/one_qubit/one_qubit_decompose.py b/qiskit/synthesis/one_qubit/one_qubit_decompose.py index f60f20f9524e..60da6ed6e82b 100644 --- a/qiskit/synthesis/one_qubit/one_qubit_decompose.py +++ b/qiskit/synthesis/one_qubit/one_qubit_decompose.py @@ -224,7 +224,8 @@ def _decompose(self, unitary, simplify=True, atol=DEFAULT_ATOL): return QuantumCircuit._from_circuit_data( euler_one_qubit_decomposer.unitary_to_circuit( unitary, [self.basis], 0, None, simplify, atol - ) + ), + add_regs=True, ) @property diff --git a/qiskit/synthesis/permutation/permutation_full.py b/qiskit/synthesis/permutation/permutation_full.py index 2fd892a0427e..7dd5ae99dc4c 100644 --- a/qiskit/synthesis/permutation/permutation_full.py +++ b/qiskit/synthesis/permutation/permutation_full.py @@ -42,7 +42,7 @@ def synth_permutation_basic(pattern: list[int] | np.ndarray[int]) -> QuantumCirc Returns: The synthesized quantum circuit. """ - return QuantumCircuit._from_circuit_data(_synth_permutation_basic(pattern)) + return QuantumCircuit._from_circuit_data(_synth_permutation_basic(pattern), add_regs=True) def synth_permutation_acg(pattern: list[int] | np.ndarray[int]) -> QuantumCircuit: @@ -75,4 +75,4 @@ def synth_permutation_acg(pattern: list[int] | np.ndarray[int]) -> QuantumCircui *Routing Permutations on Graphs Via Matchings.*, `(Full paper) `_ """ - return QuantumCircuit._from_circuit_data(_synth_permutation_acg(pattern)) + return QuantumCircuit._from_circuit_data(_synth_permutation_acg(pattern), add_regs=True) diff --git a/qiskit/synthesis/permutation/permutation_lnn.py b/qiskit/synthesis/permutation/permutation_lnn.py index d5da6929463c..5f1bfbeaa1a8 100644 --- a/qiskit/synthesis/permutation/permutation_lnn.py +++ b/qiskit/synthesis/permutation/permutation_lnn.py @@ -49,4 +49,6 @@ def synth_permutation_depth_lnn_kms(pattern: list[int] | np.ndarray[int]) -> Qua # In the permutation synthesis code below the notation is opposite: # [2, 4, 3, 0, 1] means that 0 maps to 2, 1 to 3, 2 to 3, 3 to 0, and 4 to 1. # This is why we invert the pattern. - return QuantumCircuit._from_circuit_data(_synth_permutation_depth_lnn_kms(pattern)) + return QuantumCircuit._from_circuit_data( + _synth_permutation_depth_lnn_kms(pattern), add_regs=True + ) diff --git a/qiskit/synthesis/permutation/permutation_reverse_lnn.py b/qiskit/synthesis/permutation/permutation_reverse_lnn.py index f214fd7ce294..ccc820d97e62 100644 --- a/qiskit/synthesis/permutation/permutation_reverse_lnn.py +++ b/qiskit/synthesis/permutation/permutation_reverse_lnn.py @@ -88,4 +88,6 @@ def synth_permutation_reverse_lnn_kms(num_qubits: int) -> QuantumCircuit: """ # Call Rust implementation - return QuantumCircuit._from_circuit_data(synth_permutation_reverse_lnn_kms_inner(num_qubits)) + return QuantumCircuit._from_circuit_data( + synth_permutation_reverse_lnn_kms_inner(num_qubits), add_regs=True + ) diff --git a/qiskit/synthesis/two_qubit/two_qubit_decompose.py b/qiskit/synthesis/two_qubit/two_qubit_decompose.py index 633de3a64f78..0e3427773387 100644 --- a/qiskit/synthesis/two_qubit/two_qubit_decompose.py +++ b/qiskit/synthesis/two_qubit/two_qubit_decompose.py @@ -233,7 +233,7 @@ def circuit( circuit_data = self._inner_decomposition.circuit( euler_basis=euler_basis, simplify=simplify, atol=atol ) - return QuantumCircuit._from_circuit_data(circuit_data) + return QuantumCircuit._from_circuit_data(circuit_data, add_regs=True) def actual_fidelity(self, **kwargs) -> float: """Calculates the actual fidelity of the decomposed circuit to the input unitary.""" @@ -672,7 +672,7 @@ def __call__( approximate, _num_basis_uses=_num_basis_uses, ) - return QuantumCircuit._from_circuit_data(circ_data) + return QuantumCircuit._from_circuit_data(circ_data, add_regs=True) else: sequence = self._inner_decomposer( np.asarray(unitary, dtype=complex), diff --git a/releasenotes/notes/fix-synth-qregs-7662681c0ff02511.yaml b/releasenotes/notes/fix-synth-qregs-7662681c0ff02511.yaml new file mode 100644 index 000000000000..d838032ffaf9 --- /dev/null +++ b/releasenotes/notes/fix-synth-qregs-7662681c0ff02511.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixed a bug where various synthesis methods created circuits without quantum or + classical registers. This also affected functions that internally used the synthesis + methods, such as :meth:`.Clifford.to_circuit`. + Fixed `#13041 `__. diff --git a/test/python/quantum_info/operators/symplectic/test_clifford.py b/test/python/quantum_info/operators/symplectic/test_clifford.py index 061348c78cdb..e78feaf3b78f 100644 --- a/test/python/quantum_info/operators/symplectic/test_clifford.py +++ b/test/python/quantum_info/operators/symplectic/test_clifford.py @@ -598,6 +598,23 @@ def test_to_circuit(self, num_qubits): # Convert back to clifford and check it is the same self.assertEqual(Clifford(decomp), target) + def test_to_circuit_manual(self): + """Test a manual comparison to a known circuit. + + This also tests whether the resulting Clifford circuit has quantum registers, thereby + regression testing #13041. + """ + # this is set to a circuit that remains the same under Clifford reconstruction + circuit = QuantumCircuit(2) + circuit.z(0) + circuit.h(0) + circuit.cx(0, 1) + + cliff = Clifford(circuit) + reconstructed = cliff.to_circuit() + + self.assertEqual(circuit, reconstructed) + @combine(num_qubits=[1, 2, 3, 4, 5]) def test_to_instruction(self, num_qubits): """Test to_instruction method""" From 8929e12bab1cefb429eb1ea3b59a9f98a2b09c55 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 10 Sep 2024 17:30:00 +0200 Subject: [PATCH 65/85] Fix the matrix representation of CUGate in Rust (#13121) Co-authored-by: Matthew Treinish --- crates/circuit/src/gate_matrix.rs | 4 ++-- releasenotes/notes/fix-cu-rust-6464b6893ecca1b3.yaml | 9 +++++++++ test/python/circuit/test_rust_equivalence.py | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/fix-cu-rust-6464b6893ecca1b3.yaml diff --git a/crates/circuit/src/gate_matrix.rs b/crates/circuit/src/gate_matrix.rs index a38783ef7e7f..6b04b8512fb0 100644 --- a/crates/circuit/src/gate_matrix.rs +++ b/crates/circuit/src/gate_matrix.rs @@ -387,12 +387,12 @@ pub fn cu_gate(theta: f64, phi: f64, lam: f64, gamma: f64) -> GateArray2Q { C_ZERO, c64(0., gamma).exp() * cos_theta, C_ZERO, - c64(0., gamma + phi).exp() * (-1.) * sin_theta, + c64(0., gamma + lam).exp() * (-1.) * sin_theta, ], [C_ZERO, C_ZERO, C_ONE, C_ZERO], [ C_ZERO, - c64(0., gamma + lam).exp() * sin_theta, + c64(0., gamma + phi).exp() * sin_theta, C_ZERO, c64(0., gamma + phi + lam).exp() * cos_theta, ], diff --git a/releasenotes/notes/fix-cu-rust-6464b6893ecca1b3.yaml b/releasenotes/notes/fix-cu-rust-6464b6893ecca1b3.yaml new file mode 100644 index 000000000000..406d6052a1df --- /dev/null +++ b/releasenotes/notes/fix-cu-rust-6464b6893ecca1b3.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed the definition of the :class:`.CUGate` matrix in Rust-space. + While this was not noticable while handling the :class:`.CUGate` purely on + Python side, this had knock-on effects when transpiler passes were using the + Rust representation, such as could happen in :class:`.Consolidate2qBlocks`. + Fixed `#13118 `__. + diff --git a/test/python/circuit/test_rust_equivalence.py b/test/python/circuit/test_rust_equivalence.py index b6ec28f82e8d..db4f1441bea3 100644 --- a/test/python/circuit/test_rust_equivalence.py +++ b/test/python/circuit/test_rust_equivalence.py @@ -66,7 +66,7 @@ def test_definitions(self): continue with self.subTest(name=name): - params = [pi] * standard_gate._num_params() + params = [0.1 * (i + 1) for i in range(standard_gate._num_params())] py_def = gate_class.base_class(*params).definition rs_def = standard_gate._get_definition(params) if py_def is None: @@ -141,7 +141,7 @@ def test_matrix(self): continue with self.subTest(name=name): - params = [0.1] * standard_gate._num_params() + params = [0.1 * (i + 1) for i in range(standard_gate._num_params())] py_def = gate_class.base_class(*params).to_matrix() rs_def = standard_gate._to_matrix(params) np.testing.assert_allclose(rs_def, py_def) From 49b8a5fe9a980b976f027846ce4d7b8a0217e547 Mon Sep 17 00:00:00 2001 From: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:51:28 +0200 Subject: [PATCH 66/85] Oxidize commutative cancellation (#13091) * fix * fmt * comments from code review * comments from code review * Update lib.rs * Apply suggestions from code review Co-authored-by: Matthew Treinish * code review * Fix rustfmt * Don't change interface for DAGCircuit Previously this PR was making the op_names field of the DAGCircuit struct public so it was accessible to the new transpiler pass code. However, this opened up the possibility of mutating the field by mistake, instead this makes the field private again and adds a no-copy method to get an immutable reference to the field. Additionally, there were some interface changes made to one method in DAGCircuit that were not needed anymore, which this reverts to minimize the diff. * Remove last .first().unwrap() --------- Co-authored-by: Matthew Treinish --- crates/accelerate/src/commutation_analysis.rs | 2 +- .../src/commutation_cancellation.rs | 280 ++++++++++++++++++ .../src/euler_one_qubit_decomposer.rs | 2 +- crates/accelerate/src/lib.rs | 1 + crates/circuit/src/dag_circuit.rs | 10 + crates/pyext/src/lib.rs | 14 +- qiskit/__init__.py | 1 + .../optimization/commutative_cancellation.py | 161 +--------- .../test_commutative_cancellation.py | 5 +- test/python/transpiler/test_passmanager.py | 10 +- 10 files changed, 318 insertions(+), 168 deletions(-) create mode 100644 crates/accelerate/src/commutation_cancellation.rs diff --git a/crates/accelerate/src/commutation_analysis.rs b/crates/accelerate/src/commutation_analysis.rs index 08fa1dda5ec9..2da8cfce931e 100644 --- a/crates/accelerate/src/commutation_analysis.rs +++ b/crates/accelerate/src/commutation_analysis.rs @@ -50,7 +50,7 @@ const MAX_NUM_QUBITS: u32 = 3; /// commutation_set = {0: [[0], [2, 3], [4], [1]]} /// node_indices = {(0, 0): 0, (1, 0): 3, (2, 0): 1, (3, 0): 1, (4, 0): 2} /// -fn analyze_commutations_inner( +pub(crate) fn analyze_commutations_inner( py: Python, dag: &mut DAGCircuit, commutation_checker: &mut CommutationChecker, diff --git a/crates/accelerate/src/commutation_cancellation.rs b/crates/accelerate/src/commutation_cancellation.rs new file mode 100644 index 000000000000..dc2d4436d83a --- /dev/null +++ b/crates/accelerate/src/commutation_cancellation.rs @@ -0,0 +1,280 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use std::f64::consts::PI; + +use hashbrown::{HashMap, HashSet}; +use pyo3::exceptions::PyRuntimeError; +use pyo3::prelude::*; +use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyResult, Python}; +use rustworkx_core::petgraph::stable_graph::NodeIndex; +use smallvec::{smallvec, SmallVec}; + +use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType, Wire}; +use qiskit_circuit::operations::StandardGate::{ + CXGate, CYGate, CZGate, HGate, PhaseGate, RXGate, RZGate, SGate, TGate, U1Gate, XGate, YGate, + ZGate, +}; +use qiskit_circuit::operations::{Operation, Param, StandardGate}; +use qiskit_circuit::Qubit; + +use crate::commutation_analysis::analyze_commutations_inner; +use crate::commutation_checker::CommutationChecker; +use crate::{euler_one_qubit_decomposer, QiskitError}; + +const _CUTOFF_PRECISION: f64 = 1e-5; +static ROTATION_GATES: [&str; 4] = ["p", "u1", "rz", "rx"]; +static HALF_TURNS: [&str; 2] = ["z", "x"]; +static QUARTER_TURNS: [&str; 1] = ["s"]; +static EIGHTH_TURNS: [&str; 1] = ["t"]; + +static VAR_Z_MAP: [(&str, StandardGate); 3] = [("rz", RZGate), ("p", PhaseGate), ("u1", U1Gate)]; +static Z_ROTATIONS: [StandardGate; 6] = [PhaseGate, ZGate, U1Gate, RZGate, TGate, SGate]; +static X_ROTATIONS: [StandardGate; 2] = [XGate, RXGate]; +static SUPPORTED_GATES: [StandardGate; 5] = [CXGate, CYGate, CZGate, HGate, YGate]; + +#[derive(Hash, Eq, PartialEq, Debug)] +enum GateOrRotation { + Gate(StandardGate), + ZRotation, + XRotation, +} +#[derive(Hash, Eq, PartialEq, Debug)] +struct CancellationSetKey { + gate: GateOrRotation, + qubits: SmallVec<[Qubit; 2]>, + com_set_index: usize, + second_index: Option, +} + +#[pyfunction] +#[pyo3(signature = (dag, commutation_checker, basis_gates=None))] +pub(crate) fn cancel_commutations( + py: Python, + dag: &mut DAGCircuit, + commutation_checker: &mut CommutationChecker, + basis_gates: Option>, +) -> PyResult<()> { + let basis: HashSet = if let Some(basis) = basis_gates { + basis + } else { + HashSet::new() + }; + let z_var_gate = dag + .get_op_counts() + .keys() + .find_map(|g| { + VAR_Z_MAP + .iter() + .find(|(key, _)| *key == g.as_str()) + .map(|(_, gate)| gate) + }) + .or_else(|| { + basis.iter().find_map(|g| { + VAR_Z_MAP + .iter() + .find(|(key, _)| *key == g.as_str()) + .map(|(_, gate)| gate) + }) + }); + // Fallback to the first matching key from basis if there is no match in dag.op_names + + // Gate sets to be cancelled + /* Traverse each qubit to generate the cancel dictionaries + Cancel dictionaries: + - For 1-qubit gates the key is (gate_type, qubit_id, commutation_set_id), + the value is the list of gates that share the same gate type, qubit, commutation set. + - For 2qbit gates the key: (gate_type, first_qbit, sec_qbit, first commutation_set_id, + sec_commutation_set_id), the value is the list gates that share the same gate type, + qubits and commutation sets. + */ + let (commutation_set, node_indices) = analyze_commutations_inner(py, dag, commutation_checker)?; + let mut cancellation_sets: HashMap> = HashMap::new(); + + (0..dag.num_qubits() as u32).for_each(|qubit| { + let wire = Qubit(qubit); + if let Some(wire_commutation_set) = commutation_set.get(&Wire::Qubit(wire)) { + for (com_set_idx, com_set) in wire_commutation_set.iter().enumerate() { + if let Some(&nd) = com_set.first() { + if !matches!(dag.dag[nd], NodeType::Operation(_)) { + continue; + } + } else { + continue; + } + for node in com_set.iter() { + let instr = match &dag.dag[*node] { + NodeType::Operation(instr) => instr, + _ => panic!("Unexpected type in commutation set."), + }; + let num_qargs = dag.get_qargs(instr.qubits).len(); + // no support for cancellation of parameterized gates + if instr.is_parameterized() { + continue; + } + if let Some(op_gate) = instr.op.try_standard_gate() { + if num_qargs == 1 && SUPPORTED_GATES.contains(&op_gate) { + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::Gate(op_gate), + qubits: smallvec![wire], + com_set_index: com_set_idx, + second_index: None, + }) + .or_insert_with(Vec::new) + .push(*node); + } + + if num_qargs == 1 && Z_ROTATIONS.contains(&op_gate) { + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::ZRotation, + qubits: smallvec![wire], + com_set_index: com_set_idx, + second_index: None, + }) + .or_insert_with(Vec::new) + .push(*node); + } + if num_qargs == 1 && X_ROTATIONS.contains(&op_gate) { + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::XRotation, + qubits: smallvec![wire], + com_set_index: com_set_idx, + second_index: None, + }) + .or_insert_with(Vec::new) + .push(*node); + } + // Don't deal with Y rotation, because Y rotation doesn't commute with + // CNOT, so it should be dealt with by optimized1qgate pass + if num_qargs == 2 && dag.get_qargs(instr.qubits)[0] == wire { + let second_qarg = dag.get_qargs(instr.qubits)[1]; + cancellation_sets + .entry(CancellationSetKey { + gate: GateOrRotation::Gate(op_gate), + qubits: smallvec![wire, second_qarg], + com_set_index: com_set_idx, + second_index: node_indices + .get(&(*node, Wire::Qubit(second_qarg))) + .copied(), + }) + .or_insert_with(Vec::new) + .push(*node); + } + } + } + } + } + }); + + for (cancel_key, cancel_set) in &cancellation_sets { + if cancel_set.len() > 1 { + if let GateOrRotation::Gate(g) = cancel_key.gate { + if SUPPORTED_GATES.contains(&g) { + for &c_node in &cancel_set[0..(cancel_set.len() / 2) * 2] { + dag.remove_op_node(c_node); + } + } + continue; + } + if matches!(cancel_key.gate, GateOrRotation::ZRotation) && z_var_gate.is_none() { + continue; + } + if matches!( + cancel_key.gate, + GateOrRotation::ZRotation | GateOrRotation::XRotation + ) { + let mut total_angle: f64 = 0.0; + let mut total_phase: f64 = 0.0; + for current_node in cancel_set { + let node_op = match &dag.dag[*current_node] { + NodeType::Operation(instr) => instr, + _ => panic!("Unexpected type in commutation set run."), + }; + let node_op_name = node_op.op.name(); + + let node_angle = if ROTATION_GATES.contains(&node_op_name) { + match node_op.params_view().first() { + Some(Param::Float(f)) => Ok(*f), + _ => return Err(QiskitError::new_err(format!( + "Rotational gate with parameter expression encountered in cancellation {:?}", + node_op.op + ))) + } + } else if HALF_TURNS.contains(&node_op_name) { + Ok(PI) + } else if QUARTER_TURNS.contains(&node_op_name) { + Ok(PI / 2.0) + } else if EIGHTH_TURNS.contains(&node_op_name) { + Ok(PI / 4.0) + } else { + Err(PyRuntimeError::new_err(format!( + "Angle for operation {} is not defined", + node_op_name + ))) + }; + total_angle += node_angle?; + + let Param::Float(new_phase) = node_op + .op + .definition(node_op.params_view()) + .unwrap() + .global_phase() + .clone() + else { + unreachable!() + }; + total_phase += new_phase + } + + let new_op = match cancel_key.gate { + GateOrRotation::ZRotation => z_var_gate.unwrap(), + GateOrRotation::XRotation => &RXGate, + _ => unreachable!(), + }; + + let gate_angle = euler_one_qubit_decomposer::mod_2pi(total_angle, 0.); + + let new_op_phase: f64 = if gate_angle.abs() > _CUTOFF_PRECISION { + dag.insert_1q_on_incoming_qubit((*new_op, &[total_angle]), cancel_set[0]); + let Param::Float(new_phase) = new_op + .definition(&[Param::Float(total_angle)]) + .unwrap() + .global_phase() + .clone() + else { + unreachable!(); + }; + new_phase + } else { + 0.0 + }; + + dag.add_global_phase(py, &Param::Float(total_phase - new_op_phase))?; + + for node in cancel_set { + dag.remove_op_node(*node); + } + } + } + } + + Ok(()) +} + +#[pymodule] +pub fn commutation_cancellation(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(cancel_commutations))?; + Ok(()) +} diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index a3cb11ea45a2..4c0a8539cf34 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -924,7 +924,7 @@ pub fn det_one_qubit(mat: ArrayView2) -> Complex64 { /// Wrap angle into interval [-π,π). If within atol of the endpoint, clamp to -π #[inline] -fn mod_2pi(angle: f64, atol: f64) -> f64 { +pub(crate) fn mod_2pi(angle: f64, atol: f64) -> f64 { // f64::rem_euclid() isn't exactly the same as Python's % operator, but because // the RHS here is a constant and positive it is effectively equivalent for // this case diff --git a/crates/accelerate/src/lib.rs b/crates/accelerate/src/lib.rs index 9e391e0a9030..9111f932e270 100644 --- a/crates/accelerate/src/lib.rs +++ b/crates/accelerate/src/lib.rs @@ -17,6 +17,7 @@ use pyo3::import_exception; pub mod check_map; pub mod circuit_library; pub mod commutation_analysis; +pub mod commutation_cancellation; pub mod commutation_checker; pub mod convert_2q_block_matrix; pub mod dense_layout; diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 0b5a43c1eb4b..81dd8ffd3322 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -6454,6 +6454,16 @@ impl DAGCircuit { } } + /// Get an immutable reference to the op counts for this DAGCircuit + /// + /// This differs from count_ops() in that it doesn't handle control flow recursion at all + /// and it returns a reference instead of an owned copy. If you don't need to work with + /// control flow or ownership of the counts this is a more efficient alternative to + /// `DAGCircuit::count_ops(py, false)` + pub fn get_op_counts(&self) -> &IndexMap { + &self.op_names + } + /// Extends the DAG with valid instances of [PackedInstruction] pub fn extend(&mut self, py: Python, iter: I) -> PyResult> where diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 03bd0202dae4..43b693a4d6c1 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -14,12 +14,13 @@ use pyo3::prelude::*; use qiskit_accelerate::{ check_map::check_map_mod, circuit_library::circuit_library, - commutation_analysis::commutation_analysis, commutation_checker::commutation_checker, - convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout, - error_map::error_map, euler_one_qubit_decomposer::euler_one_qubit_decomposer, - filter_op_nodes::filter_op_nodes_mod, gate_direction::gate_direction, - inverse_cancellation::inverse_cancellation_mod, isometry::isometry, nlayout::nlayout, - optimize_1q_gates::optimize_1q_gates, pauli_exp_val::pauli_expval, + commutation_analysis::commutation_analysis, commutation_cancellation::commutation_cancellation, + commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix, + dense_layout::dense_layout, error_map::error_map, + euler_one_qubit_decomposer::euler_one_qubit_decomposer, filter_op_nodes::filter_op_nodes_mod, + gate_direction::gate_direction, inverse_cancellation::inverse_cancellation_mod, + isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates, + pauli_exp_val::pauli_expval, remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results, sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op, split_2q_unitaries::split_2q_unitaries_mod, star_prerouting::star_prerouting, @@ -77,5 +78,6 @@ fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, gate_direction, "gate_direction")?; add_submodule(m, commutation_checker, "commutation_checker")?; add_submodule(m, commutation_analysis, "commutation_analysis")?; + add_submodule(m, commutation_cancellation, "commutation_cancellation")?; Ok(()) } diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 29e2b8ba5c11..d0811c172d69 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -91,6 +91,7 @@ sys.modules["qiskit._accelerate.synthesis.clifford"] = _accelerate.synthesis.clifford sys.modules["qiskit._accelerate.commutation_checker"] = _accelerate.commutation_checker sys.modules["qiskit._accelerate.commutation_analysis"] = _accelerate.commutation_analysis +sys.modules["qiskit._accelerate.commutation_cancellation"] = _accelerate.commutation_cancellation sys.modules["qiskit._accelerate.synthesis.linear_phase"] = _accelerate.synthesis.linear_phase sys.modules["qiskit._accelerate.split_2q_unitaries"] = _accelerate.split_2q_unitaries sys.modules["qiskit._accelerate.gate_direction"] = _accelerate.gate_direction diff --git a/qiskit/transpiler/passes/optimization/commutative_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_cancellation.py index 836fa112fd84..130ff0609354 100644 --- a/qiskit/transpiler/passes/optimization/commutative_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_cancellation.py @@ -11,23 +11,16 @@ # that they have been altered from the originals. """Cancel the redundant (self-adjoint) gates through commutation relations.""" - -from collections import defaultdict -import numpy as np - -from qiskit.circuit.quantumregister import QuantumRegister -from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.transpiler.basepasses import TransformationPass -from qiskit.transpiler.passmanager import PassManager -from qiskit.transpiler.passes.optimization.commutation_analysis import CommutationAnalysis -from qiskit.dagcircuit import DAGCircuit, DAGInNode, DAGOutNode -from qiskit.circuit.commutation_library import CommutationChecker, StandardGateCommutations +from qiskit.circuit.commutation_library import StandardGateCommutations + from qiskit.circuit.library.standard_gates.u1 import U1Gate -from qiskit.circuit.library.standard_gates.rx import RXGate from qiskit.circuit.library.standard_gates.p import PhaseGate from qiskit.circuit.library.standard_gates.rz import RZGate -from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES +from qiskit._accelerate import commutation_cancellation +from qiskit._accelerate.commutation_checker import CommutationChecker +from qiskit.transpiler.passes.utils.control_flow import trivial_recurse _CUTOFF_PRECISION = 1e-5 @@ -59,6 +52,7 @@ def __init__(self, basis_gates=None, target=None): self.basis = set(basis_gates) else: self.basis = set() + self.target = target if target is not None: self.basis = set(target.operation_names) @@ -70,12 +64,11 @@ def __init__(self, basis_gates=None, target=None): # build a commutation checker restricted to the gates we cancel -- the others we # do not have to investigate, which allows to save time - commutation_checker = CommutationChecker( + self._commutation_checker = CommutationChecker( StandardGateCommutations, gates=self._gates | self._z_rotations | self._x_rotations ) - self.requires.append(CommutationAnalysis(_commutation_checker=commutation_checker)) - + @trivial_recurse def run(self, dag): """Run the CommutativeCancellation pass on `dag`. @@ -85,141 +78,5 @@ def run(self, dag): Returns: DAGCircuit: the optimized DAG. """ - var_z_gate = None - z_var_gates = [gate for gate in dag.count_ops().keys() if gate in self._var_z_map] - if z_var_gates: - # prioritize z gates in circuit - var_z_gate = self._var_z_map[next(iter(z_var_gates))] - else: - z_var_gates = [gate for gate in self.basis if gate in self._var_z_map] - if z_var_gates: - var_z_gate = self._var_z_map[next(iter(z_var_gates))] - - # Gate sets to be cancelled - cancellation_sets = defaultdict(lambda: []) - - # Traverse each qubit to generate the cancel dictionaries - # Cancel dictionaries: - # - For 1-qubit gates the key is (gate_type, qubit_id, commutation_set_id), - # the value is the list of gates that share the same gate type, qubit, commutation set. - # - For 2qbit gates the key: (gate_type, first_qbit, sec_qbit, first commutation_set_id, - # sec_commutation_set_id), the value is the list gates that share the same gate type, - # qubits and commutation sets. - for wire in dag.qubits: - wire_commutation_set = self.property_set["commutation_set"][wire] - - for com_set_idx, com_set in enumerate(wire_commutation_set): - if isinstance(com_set[0], (DAGInNode, DAGOutNode)): - continue - for node in com_set: - num_qargs = len(node.qargs) - if any(isinstance(p, ParameterExpression) for p in node.params): - continue # no support for cancellation of parameterized gates - if num_qargs == 1 and node.name in self._gates: - cancellation_sets[(node.name, wire, com_set_idx)].append(node) - if num_qargs == 1 and node.name in self._z_rotations: - cancellation_sets[("z_rotation", wire, com_set_idx)].append(node) - if num_qargs == 1 and node.name in ["rx", "x"]: - cancellation_sets[("x_rotation", wire, com_set_idx)].append(node) - # Don't deal with Y rotation, because Y rotation doesn't commute with CNOT, so - # it should be dealt with by optimized1qgate pass - elif num_qargs == 2 and node.qargs[0] == wire: - second_qarg = node.qargs[1] - q2_key = ( - node.name, - wire, - second_qarg, - com_set_idx, - self.property_set["commutation_set"][(node, second_qarg)], - ) - cancellation_sets[q2_key].append(node) - - for cancel_set_key in cancellation_sets: - if cancel_set_key[0] == "z_rotation" and var_z_gate is None: - continue - set_len = len(cancellation_sets[cancel_set_key]) - if set_len > 1 and cancel_set_key[0] in self._gates: - gates_to_cancel = cancellation_sets[cancel_set_key] - for c_node in gates_to_cancel[: (set_len // 2) * 2]: - dag.remove_op_node(c_node) - - elif set_len > 1 and cancel_set_key[0] in ["z_rotation", "x_rotation"]: - run = cancellation_sets[cancel_set_key] - run_qarg = run[0].qargs[0] - total_angle = 0.0 # lambda - total_phase = 0.0 - for current_node in run: - if ( - current_node.condition is not None - or len(current_node.qargs) != 1 - or current_node.qargs[0] != run_qarg - ): - raise RuntimeError("internal error") - - if current_node.name in ["p", "u1", "rz", "rx"]: - current_angle = float(current_node.params[0]) - elif current_node.name in ["z", "x"]: - current_angle = np.pi - elif current_node.name == "t": - current_angle = np.pi / 4 - elif current_node.name == "s": - current_angle = np.pi / 2 - else: - raise RuntimeError( - f"Angle for operation {current_node.name } is not defined" - ) - - # Compose gates - total_angle = current_angle + total_angle - if current_node.definition: - total_phase += current_node.definition.global_phase - - # Replace the data of the first node in the run - if cancel_set_key[0] == "z_rotation": - new_op = var_z_gate(total_angle) - elif cancel_set_key[0] == "x_rotation": - new_op = RXGate(total_angle) - else: - raise RuntimeError("impossible case") - - new_op_phase = 0 - if np.mod(total_angle, (2 * np.pi)) > _CUTOFF_PRECISION: - new_qarg = QuantumRegister(1, "q") - new_dag = DAGCircuit() - new_dag.add_qreg(new_qarg) - new_dag.apply_operation_back(new_op, [new_qarg[0]]) - dag.substitute_node_with_dag(run[0], new_dag) - if new_op.definition: - new_op_phase = new_op.definition.global_phase - - dag.global_phase = total_phase - new_op_phase - - # Delete the other nodes in the run - for current_node in run[1:]: - dag.remove_op_node(current_node) - - if np.mod(total_angle, (2 * np.pi)) < _CUTOFF_PRECISION: - dag.remove_op_node(run[0]) - - dag = self._handle_control_flow_ops(dag) - - return dag - - def _handle_control_flow_ops(self, dag): - """ - This is similar to transpiler/passes/utils/control_flow.py except that the - commutation analysis is redone for the control flow blocks. - """ - - pass_manager = PassManager([CommutationAnalysis(), self]) - for node in dag.op_nodes(): - if node.name not in CONTROL_FLOW_OP_NAMES: - continue - mapped_blocks = [] - for block in node.op.blocks: - new_circ = pass_manager.run(block) - mapped_blocks.append(new_circ) - dag.substitute_node( - node, node.op.replace_blocks(mapped_blocks), propagate_condition=False - ) + commutation_cancellation.cancel_commutations(dag, self._commutation_checker, self.basis) return dag diff --git a/test/python/transpiler/test_commutative_cancellation.py b/test/python/transpiler/test_commutative_cancellation.py index 71bab61708cd..88f1d99bef31 100644 --- a/test/python/transpiler/test_commutative_cancellation.py +++ b/test/python/transpiler/test_commutative_cancellation.py @@ -13,6 +13,7 @@ """Gate cancellation pass testing""" import unittest + import numpy as np from qiskit import QuantumRegister, QuantumCircuit @@ -76,7 +77,7 @@ def test_all_gates(self): expected = QuantumCircuit(qr) expected.append(RZGate(2.0), [qr[0]]) expected.rx(1.0, qr[0]) - + expected.global_phase = 0.5 self.assertEqual(expected, new_circuit) def test_commutative_circuit1(self): @@ -433,7 +434,7 @@ def test_commutative_circuit3(self): expected.append(RZGate(np.pi * 17 / 12), [qr[2]]) expected.append(RZGate(np.pi * 2 / 3), [qr[3]]) expected.cx(qr[2], qr[1]) - + expected.global_phase = 3 * np.pi / 8 self.assertEqual( expected, new_circuit, msg=f"expected:\n{expected}\nnew_circuit:\n{new_circuit}" ) diff --git a/test/python/transpiler/test_passmanager.py b/test/python/transpiler/test_passmanager.py index ce4d28bf314e..60375a820655 100644 --- a/test/python/transpiler/test_passmanager.py +++ b/test/python/transpiler/test_passmanager.py @@ -27,7 +27,7 @@ DoWhileController, ) from qiskit.transpiler import PassManager, PropertySet, TransformationPass -from qiskit.transpiler.passes import CommutativeCancellation +from qiskit.transpiler.passes import RXCalibrationBuilder from qiskit.transpiler.passes import Optimize1qGates, BasisTranslator from qiskit.circuit.library.standard_gates.equivalence_library import ( StandardEquivalenceLibrary as std_eqlib, @@ -97,7 +97,6 @@ def test_callback_with_pass_requires(self): expected_end = QuantumCircuit(qr) expected_end.cx(qr[0], qr[2]) - expected_end_dag = circuit_to_dag(expected_end) calls = [] @@ -107,20 +106,19 @@ def callback(**kwargs): calls.append(out_dict) passmanager = PassManager() - passmanager.append(CommutativeCancellation(basis_gates=["u1", "u2", "u3", "cx"])) + passmanager.append(RXCalibrationBuilder()) passmanager.run(circuit, callback=callback) self.assertEqual(len(calls), 2) self.assertEqual(len(calls[0]), 5) self.assertEqual(calls[0]["count"], 0) - self.assertEqual(calls[0]["pass_"].name(), "CommutationAnalysis") + self.assertEqual(calls[0]["pass_"].name(), "NormalizeRXAngle") self.assertEqual(expected_start_dag, calls[0]["dag"]) self.assertIsInstance(calls[0]["time"], float) self.assertIsInstance(calls[0]["property_set"], PropertySet) self.assertEqual("MyCircuit", calls[0]["dag"].name) self.assertEqual(len(calls[1]), 5) self.assertEqual(calls[1]["count"], 1) - self.assertEqual(calls[1]["pass_"].name(), "CommutativeCancellation") - self.assertEqual(expected_end_dag, calls[1]["dag"]) + self.assertEqual(calls[1]["pass_"].name(), "RXCalibrationBuilder") self.assertIsInstance(calls[0]["time"], float) self.assertIsInstance(calls[0]["property_set"], PropertySet) self.assertEqual("MyCircuit", calls[1]["dag"].name) From 86a1b496ac44698422c0428b9d76820148c2a707 Mon Sep 17 00:00:00 2001 From: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:23:21 -0400 Subject: [PATCH 67/85] Port `circuit_to_dag` to Rust (#13036) * Initial: Add add_from_iter method to DAGCircuit - Introduce a method that adds a chain of `PackedInstruction` continuously avoiding the re-linking of each bit's output-node until the very end of the iterator. - TODO: Add handling of vars - Add header for a `from_iter` function that will create a `DAGCircuit` based on a chain of `PackedInstruction`. * Fix: leverage new methods in layers - Fix incorrect re-insertion of last_node. * Fix: Keep track of Vars for add_from_iter - Remove `from_iter` * Fix: Incorrect modification of last nodes in `add_from_iter`. - Use `entry` api to either modify or insert a value if missing. * Fix: Cycling edges in when adding vars. - A bug that adds duplicate edges to vars has been temporarily fixed. However, the root of this problem hasn't been found yet. A proper fix is pending. For now skip those instances. * Fix: Remove set collecting all nodes to be connected. - A set collecting all the new nodes to connect with a new node was preventing additional wires to connect to subsequent nodes. * Fix: Adapt to #13033 * Refactor: `add_from_iter` is now called `extend` to stick with `Rust` nomenclature. * Fix: Remove duplicate vars check * Fix: Corrections from code review. - Use Entry API to modify last nodes in the var. - Build new_nodes with an allocated vec. - Add comment explaining the removal of the edge between the output node and its predecessor. * Fix: Improper use of `Entry API`. - Use `or_insert_with` instead of `or_insert` to perform actions before inserting a value. * Initial: Add add_from_iter method to DAGCircuit - Introduce a method that adds a chain of `PackedInstruction` continuously avoiding the re-linking of each bit's output-node until the very end of the iterator. - TODO: Add handling of vars - Add header for a `from_iter` function that will create a `DAGCircuit` based on a chain of `PackedInstruction`. * Initial: Expose `CircuitData` interners and registers to the `qiskit-circuit` crate. - Make the `CircuitData` iter method be an exact-size iterator. * FIx: Expose immutable views of interners, registers and global phase. - Revert the changes making the interners and registers visible to the crate `qiskit-circuit`. - Create methods to expose immutable borrowed views of the interners, registers and global_phase to prevent from mutating the DAGCircuit. - Add `get_qargs` and `get_cargs` to unpack interned qargs ans cargs. - Other tweaks and fixes. * Refactor: Use naming convention for getters. * Docs: Apply suggestions from code review - Correct incorrect docstrings for `qubits()` and `clbits()` Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> * Initial: Add `circuit_to_dag` in rust. - Add new method `DAGCircuit::from_quantum_circuit` which uses the data from a `QuantumCircuit` instance to build a dag_circuit. - Expose the method through a `Python` interface with `circuit_to_dag` which goes by the alias of `core_circuit_to_dag` and is called by the original method. - Add an arbitrary structure `QuantumCircuitData` that successfully extract attributes from the python `QuantumCircuit` instance and makes it easier to access in rust. - This structure is for attribute extraction only and is not clonable/copyable. - Expose a new module `converters` which should store all of the rust-side converters whenever they get brought into rust. - Other small tweaks and fixes. * Fix: Move qubit ordering check to python - Add more accurate estimate of num_edges. * Fix: Regenerate `BitData` instances dynamically instead of cloning. - When converting from `QuantumCircuit` to `DAGCircuit`, we were previously copying the instances of `BitData` by cloning. This would result in instances that had extra qubits that went unused. This commit fixes this oversight and reduced the amount of failing times from 160 to 12. * Fix: Make use of `copy_operations` - Use `copy_operations` to copy all of the operations obtained from `CircuitData` by calling deepcopy. - Initialize `._data` manually for instances of `BlueprintCircuit` by calling `._build()`. - Other small fixes. * FIx: Adapt to 13033 * Fix: Correctly map qubits and clbits to the `DAGCircuit`. - Previously, the binding of qubits and clbits into bitdata was done based on the `push_back()` function behavior. This manual mapping was removed in favor of just inserting the qubits/clbits using the `add_qubits()` and `add_clbits()` methods and keeping track of the new indices. - Remove cloning of interners, use the re-mapped entries instead. - Remove manual re-mapping of qubits and clbits. - Remove cloning of BitData, insert qubits directly instead. - Other small tweaks and fixes. * Add: `DAGCircuit` from `CircuitData` - Make `QuantumCircuitData` extraction struct private. - Rename `DAGCircuit::from_quantum_circuit` into `DAGCircuit::from_circuit` to make more generalized. - Pass all attributes of `QuantumCircuit` that are passed from python as arguments to the `DAGCircuit::from_circuit` function. - Add `DAGCircuit::from_circuit_data` as a wrapper to `from_circuit` to create an instance solely from the properties available in `CircuitData`. - Use `DAGCircuit::from_circuit` as base for `DAGCircuit::from_circuit_data`. * Fix: Make `QuantumCircuitData` public. - `QuantumCircuitData` is an extractor helper built only to extract attributes from a Python-based `Quantumircuit` that are not yet available in rust + the qualities that already are through `CircuitData`. - Add `Clone` trait `QuantumCircuitData` as all its properties are clonable. - Make `circuit_to_dag` public in rust in case it needs to be used for a transpiler pass. - Adapt to renaming of `DAGCircuit::add_from_iter` into `DAGCircuit::extend`. * Fix: Use `intern!` when extracting attributes from Python. * Fix: Copy instructions in place instead of copying circuit data. - Use `QuantumCircuitData` as argument for `DAGCircuit::from_circuit`. - Create instance of `QuantumCircuitData` in `DAGCircuit::from_circuit_data`. - Re-add duplicate skip in extend. - Other tweaks and fixes. * Fix: Remove second re-mapping of bits - Remove second re-mapping of bits, perform this mapping at insertion of qubits instead. - Modify insertion of qubits to re-map the indices and store them after insertion should a custom ordering be provided. - Remove extra `.and_modify()` for `clbits_last_node` from `DAGCircuit::extend`. - Remove submodule addition to `circuit` module, submodule is now under `_accelerate.converters`. - Other tweaks and fixes. * Update crates/circuit/src/dag_circuit.rs Co-authored-by: Matthew Treinish --------- Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Co-authored-by: Matthew Treinish --- crates/circuit/src/converters.rs | 91 ++++++++++++ crates/circuit/src/dag_circuit.rs | 208 ++++++++++++++++++++++++++++ crates/circuit/src/lib.rs | 1 + crates/pyext/src/lib.rs | 1 + qiskit/__init__.py | 1 + qiskit/converters/circuit_to_dag.py | 52 ++----- 6 files changed, 316 insertions(+), 38 deletions(-) create mode 100644 crates/circuit/src/converters.rs diff --git a/crates/circuit/src/converters.rs b/crates/circuit/src/converters.rs new file mode 100644 index 000000000000..ab9d4bce0475 --- /dev/null +++ b/crates/circuit/src/converters.rs @@ -0,0 +1,91 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2023, 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use ::pyo3::prelude::*; +use hashbrown::HashMap; +use pyo3::{ + intern, + types::{PyDict, PyList}, +}; + +use crate::{circuit_data::CircuitData, dag_circuit::DAGCircuit}; + +/// An extractable representation of a QuantumCircuit reserved only for +/// conversion purposes. +#[derive(Debug, Clone)] +pub struct QuantumCircuitData<'py> { + pub data: CircuitData, + pub name: Option>, + pub calibrations: Option>>, + pub metadata: Option>, + pub qregs: Option>, + pub cregs: Option>, + pub input_vars: Vec>, + pub captured_vars: Vec>, + pub declared_vars: Vec>, +} + +impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { + let py = ob.py(); + let circuit_data = ob.getattr("_data")?; + let data_borrowed = circuit_data.extract::()?; + Ok(QuantumCircuitData { + data: data_borrowed, + name: ob.getattr(intern!(py, "name")).ok(), + calibrations: ob.getattr(intern!(py, "calibrations"))?.extract().ok(), + metadata: ob.getattr(intern!(py, "metadata")).ok(), + qregs: ob + .getattr(intern!(py, "qregs")) + .map(|ob| ob.downcast_into())? + .ok(), + cregs: ob + .getattr(intern!(py, "cregs")) + .map(|ob| ob.downcast_into())? + .ok(), + input_vars: ob + .call_method0(intern!(py, "iter_input_vars"))? + .iter()? + .collect::>>()?, + captured_vars: ob + .call_method0(intern!(py, "iter_captured_vars"))? + .iter()? + .collect::>>()?, + declared_vars: ob + .call_method0(intern!(py, "iter_declared_vars"))? + .iter()? + .collect::>>()?, + }) + } +} + +#[pyfunction(signature = (quantum_circuit, copy_operations = true, qubit_order = None, clbit_order = None))] +pub fn circuit_to_dag( + py: Python, + quantum_circuit: QuantumCircuitData, + copy_operations: bool, + qubit_order: Option>>, + clbit_order: Option>>, +) -> PyResult { + DAGCircuit::from_circuit( + py, + quantum_circuit, + copy_operations, + qubit_order, + clbit_order, + ) +} + +pub fn converters(m: &Bound) -> PyResult<()> { + m.add_function(wrap_pyfunction!(circuit_to_dag, m)?)?; + Ok(()) +} diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 81dd8ffd3322..197ad57278a2 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -15,9 +15,11 @@ use std::hash::{Hash, Hasher}; use ahash::RandomState; use crate::bit_data::BitData; +use crate::circuit_data::CircuitData; use crate::circuit_instruction::{ CircuitInstruction, ExtraInstructionAttributes, OperationFromPython, }; +use crate::converters::QuantumCircuitData; use crate::dag_node::{DAGInNode, DAGNode, DAGOpNode, DAGOutNode}; use crate::dot_utils::build_dot; use crate::error::DAGCircuitError; @@ -6572,7 +6574,12 @@ impl DAGCircuit { predecessor_node }; + // Because `DAGCircuit::additional_wires` can return repeated instances of vars, + // we need to make sure to skip those to avoid cycles. vars_last_nodes.set_item(var, new_node.index())?; + if var_last_node == new_node { + continue; + } self.dag .add_edge(var_last_node, new_node, Wire::Var(var.clone_ref(py))); } @@ -6600,6 +6607,207 @@ impl DAGCircuit { Ok(new_nodes) } + + /// Alternative constructor to build an instance of [DAGCircuit] from a `QuantumCircuit`. + pub(crate) fn from_circuit( + py: Python, + qc: QuantumCircuitData, + copy_op: bool, + qubit_order: Option>>, + clbit_order: Option>>, + ) -> PyResult { + // Extract necessary attributes + let qc_data = qc.data; + let num_qubits = qc_data.num_qubits(); + let num_clbits = qc_data.num_clbits(); + let num_ops = qc_data.__len__(); + let num_vars = qc.declared_vars.len() + qc.input_vars.len() + qc.captured_vars.len(); + + // Build DAGCircuit with capacity + let mut new_dag = DAGCircuit::with_capacity( + py, + num_qubits, + num_clbits, + Some(num_vars), + Some(num_ops), + None, + )?; + + // Assign other necessary data + new_dag.name = qc.name.map(|ob| ob.unbind()); + + // Avoid manually acquiring the GIL. + new_dag.global_phase = match qc_data.global_phase() { + Param::ParameterExpression(exp) => Param::ParameterExpression(exp.clone_ref(py)), + Param::Float(float) => Param::Float(*float), + _ => unreachable!("Incorrect parameter assigned for global phase"), + }; + + if let Some(calibrations) = qc.calibrations { + new_dag.calibrations = calibrations; + } + + new_dag.metadata = qc.metadata.map(|meta| meta.unbind()); + + // Add the qubits depending on order. + let qubit_map: Option> = if let Some(qubit_ordering) = qubit_order { + let mut ordered_vec = Vec::from_iter((0..num_qubits as u32).map(Qubit)); + qubit_ordering + .into_iter() + .try_for_each(|qubit| -> PyResult<()> { + if new_dag.qubits.find(&qubit).is_some() { + return Err(DAGCircuitError::new_err(format!( + "duplicate qubits {}", + &qubit + ))); + } + let qubit_index = qc_data.qubits().find(&qubit).unwrap(); + ordered_vec[qubit_index.0 as usize] = + new_dag.add_qubit_unchecked(py, &qubit)?; + Ok(()) + })?; + Some(ordered_vec) + } else { + qc_data + .qubits() + .bits() + .iter() + .try_for_each(|qubit| -> PyResult<_> { + new_dag.add_qubit_unchecked(py, qubit.bind(py))?; + Ok(()) + })?; + None + }; + + // Add the clbits depending on order. + let clbit_map: Option> = if let Some(clbit_ordering) = clbit_order { + let mut ordered_vec = Vec::from_iter((0..num_clbits as u32).map(Clbit)); + clbit_ordering + .into_iter() + .try_for_each(|clbit| -> PyResult<()> { + if new_dag.clbits.find(&clbit).is_some() { + return Err(DAGCircuitError::new_err(format!( + "duplicate clbits {}", + &clbit + ))); + }; + let clbit_index = qc_data.clbits().find(&clbit).unwrap(); + ordered_vec[clbit_index.0 as usize] = + new_dag.add_clbit_unchecked(py, &clbit)?; + Ok(()) + })?; + Some(ordered_vec) + } else { + qc_data + .clbits() + .bits() + .iter() + .try_for_each(|clbit| -> PyResult<()> { + new_dag.add_clbit_unchecked(py, clbit.bind(py))?; + Ok(()) + })?; + None + }; + + // Add all of the new vars. + for var in &qc.declared_vars { + new_dag.add_var(py, var, DAGVarType::Declare)?; + } + + for var in &qc.input_vars { + new_dag.add_var(py, var, DAGVarType::Input)?; + } + + for var in &qc.captured_vars { + new_dag.add_var(py, var, DAGVarType::Capture)?; + } + + // Add all the registers + if let Some(qregs) = qc.qregs { + for qreg in qregs.iter() { + new_dag.add_qreg(py, &qreg)?; + } + } + + if let Some(cregs) = qc.cregs { + for creg in cregs.iter() { + new_dag.add_creg(py, &creg)?; + } + } + + // Pre-process and re-intern all indices again. + let instructions: Vec = qc_data + .iter() + .map(|instr| -> PyResult { + // Re-map the qubits + let new_qargs = if let Some(qubit_mapping) = &qubit_map { + let qargs = qc_data + .get_qargs(instr.qubits) + .iter() + .map(|bit| qubit_mapping[bit.0 as usize]) + .collect(); + new_dag.qargs_interner.insert_owned(qargs) + } else { + new_dag + .qargs_interner + .insert(qc_data.get_qargs(instr.qubits)) + }; + // Remap the clbits + let new_cargs = if let Some(clbit_mapping) = &clbit_map { + let qargs = qc_data + .get_cargs(instr.clbits) + .iter() + .map(|bit| clbit_mapping[bit.0 as usize]) + .collect(); + new_dag.cargs_interner.insert_owned(qargs) + } else { + new_dag + .cargs_interner + .insert(qc_data.get_cargs(instr.clbits)) + }; + // Copy the operations + + Ok(PackedInstruction { + op: if copy_op { + instr.op.py_deepcopy(py, None)? + } else { + instr.op.clone() + }, + qubits: new_qargs, + clbits: new_cargs, + params: instr.params.clone(), + extra_attrs: instr.extra_attrs.clone(), + #[cfg(feature = "cache_pygates")] + py_op: OnceCell::new(), + }) + }) + .collect::>>()?; + + // Finally add all the instructions back + new_dag.extend(py, instructions)?; + + Ok(new_dag) + } + + /// Builds a [DAGCircuit] based on an instance of [CircuitData]. + pub fn from_circuit_data( + py: Python, + circuit_data: CircuitData, + copy_op: bool, + ) -> PyResult { + let circ = QuantumCircuitData { + data: circuit_data, + name: None, + calibrations: None, + metadata: None, + qregs: None, + cregs: None, + input_vars: Vec::new(), + captured_vars: Vec::new(), + declared_vars: Vec::new(), + }; + Self::from_circuit(py, circ, copy_op, None, None) + } } /// Add to global phase. Global phase can only be Float or ParameterExpression so this diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index 5106ba030288..dcff558ade64 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -13,6 +13,7 @@ pub mod bit_data; pub mod circuit_data; pub mod circuit_instruction; +pub mod converters; pub mod dag_circuit; pub mod dag_node; mod dot_utils; diff --git a/crates/pyext/src/lib.rs b/crates/pyext/src/lib.rs index 43b693a4d6c1..6033c7c47e49 100644 --- a/crates/pyext/src/lib.rs +++ b/crates/pyext/src/lib.rs @@ -43,6 +43,7 @@ where #[pymodule] fn _accelerate(m: &Bound) -> PyResult<()> { add_submodule(m, qiskit_circuit::circuit, "circuit")?; + add_submodule(m, qiskit_circuit::converters::converters, "converters")?; add_submodule(m, qiskit_qasm2::qasm2, "qasm2")?; add_submodule(m, qiskit_qasm3::qasm3, "qasm3")?; add_submodule(m, circuit_library, "circuit_library")?; diff --git a/qiskit/__init__.py b/qiskit/__init__.py index d0811c172d69..41f9d9eba1b9 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -61,6 +61,7 @@ # and not have to rely on attribute access. No action needed for top-level extension packages. sys.modules["qiskit._accelerate.circuit"] = _accelerate.circuit sys.modules["qiskit._accelerate.circuit_library"] = _accelerate.circuit_library +sys.modules["qiskit._accelerate.converters"] = _accelerate.converters sys.modules["qiskit._accelerate.convert_2q_block_matrix"] = _accelerate.convert_2q_block_matrix sys.modules["qiskit._accelerate.dense_layout"] = _accelerate.dense_layout sys.modules["qiskit._accelerate.error_map"] = _accelerate.error_map diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index a330b8cbd682..5be9a721bafa 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -12,8 +12,8 @@ """Helper function for converting a circuit to a dag""" -from qiskit.dagcircuit.dagcircuit import DAGCircuit -from qiskit.dagcircuit.dagnode import DAGOpNode +from qiskit.circuit.library.blueprintcircuit import BlueprintCircuit +from qiskit._accelerate.converters import circuit_to_dag as core_circuit_to_dag def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_order=None): @@ -56,46 +56,22 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord circ.rz(0.5, q[1]).c_if(c, 2) dag = circuit_to_dag(circ) """ - dagcircuit = DAGCircuit() - dagcircuit.name = circuit.name - dagcircuit.global_phase = circuit.global_phase - dagcircuit.calibrations = circuit.calibrations - dagcircuit.metadata = circuit.metadata - - if qubit_order is None: - qubits = circuit.qubits - elif len(qubit_order) != circuit.num_qubits or set(qubit_order) != set(circuit.qubits): + # If we have an instance of BluePrintCircuit, make sure it is built by calling ._build() + if isinstance(circuit, BlueprintCircuit): + if not circuit._is_built: + circuit._build() + + if qubit_order is not None and ( + len(qubit_order) != circuit.num_qubits or set(qubit_order) != set(circuit.qubits) + ): raise ValueError("'qubit_order' does not contain exactly the same qubits as the circuit") - else: - qubits = qubit_order - if clbit_order is None: - clbits = circuit.clbits - elif len(clbit_order) != circuit.num_clbits or set(clbit_order) != set(circuit.clbits): + if clbit_order is not None and ( + len(clbit_order) != circuit.num_clbits or set(clbit_order) != set(circuit.clbits) + ): raise ValueError("'clbit_order' does not contain exactly the same clbits as the circuit") - else: - clbits = clbit_order - - dagcircuit.add_qubits(qubits) - dagcircuit.add_clbits(clbits) - - for var in circuit.iter_input_vars(): - dagcircuit.add_input_var(var) - for var in circuit.iter_captured_vars(): - dagcircuit.add_captured_var(var) - for var in circuit.iter_declared_vars(): - dagcircuit.add_declared_var(var) - - for register in circuit.qregs: - dagcircuit.add_qreg(register) - - for register in circuit.cregs: - dagcircuit.add_creg(register) - for instruction in circuit.data: - dagcircuit._apply_op_node_back( - DAGOpNode.from_instruction(instruction, deepcopy=copy_operations) - ) + dagcircuit = core_circuit_to_dag(circuit, copy_operations, qubit_order, clbit_order) dagcircuit.duration = circuit.duration dagcircuit.unit = circuit.unit From dd145b54be9d583d3857edfbd81e910600249adf Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 10 Sep 2024 19:53:20 -0400 Subject: [PATCH 68/85] Raise minimum python version to 3.9 (#12910) * Raise minimum python version to 3.9 Qiskit 1.2.0 was the final minor version release of qiskit with Python 3.8 support. As Python 3.8 is going EoL before the next Qiskit minor release 1.3.0 we can drop support for running with 3.8 on the main branch now. This commit makes that change and updates everything using python 3.8 currently to use our new minimum instead. * Pin dependency versions when installing historical versions Now that we're running Python 3.9 as the base version we are encountering compatibility issues with some of our dependencies because 3.9 supports newer versions of things like numpy than older Qiskit releases were compatible with. The only way to work around this is to pin the versions when installing historical versions. To start this sets a single constraints version since we can get away with using the same version for everything. In the future though it is possible that we'll need separate files for different historical releases. * Update reference images * Drop 3.8 support in asv too * Remove deprecation warning for 3.8 --- .github/workflows/coverage.yml | 2 +- .github/workflows/randomized_tests.yml | 2 +- .github/workflows/tests.yml | 2 +- .github/workflows/wheels.yml | 31 +----------------- Cargo.toml | 2 +- asv.conf.json | 2 +- azure-pipelines.yml | 4 +-- pyproject.toml | 9 +++-- qiskit/__init__.py | 8 ----- .../notes/py3.9-min-now-c9781484a0eb288e.yaml | 6 ++++ .../circuit/test_circuit_load_from_qpy.py | 12 ++++--- .../circuit/test_control_flow_builders.py | 9 +++-- test/qpy_compat/process_version.sh | 4 +-- test/qpy_compat/qpy_test_constraints.txt | 2 ++ test/qpy_compat/run_tests.sh | 2 +- .../graph/references/bloch_multivector.png | Bin 72475 -> 75579 bytes ...bloch_multivector_figsize_improvements.png | Bin 70588 -> 73633 bytes .../mpl/graph/references/state_city.png | Bin 108666 -> 107036 bytes tox.ini | 4 +-- 19 files changed, 39 insertions(+), 62 deletions(-) create mode 100644 releasenotes/notes/py3.9-min-now-c9781484a0eb288e.yaml create mode 100644 test/qpy_compat/qpy_test_constraints.txt diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 95a0bda5d421..625ea9bc1f50 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.8' + python-version: '3.11' - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/randomized_tests.yml b/.github/workflows/randomized_tests.yml index f807656a84ce..1cc39893c5ec 100644 --- a/.github/workflows/randomized_tests.yml +++ b/.github/workflows/randomized_tests.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.8' + python-version: '3.11' - name: Install dependencies run: | python -m pip install -U pip setuptools wheel diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 20e40dec9824..20c40dc38321 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - # Normally we test min and max version but we can't run python 3.8 or + # Normally we test min and max version but we can't run python # 3.9 on arm64 until actions/setup-python#808 is resolved python-version: ["3.10", "3.12"] steps: diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d7c2b8c3f783..3314bae05d5b 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -41,35 +41,6 @@ jobs: with: path: ./wheelhouse/*.whl name: wheels-${{ matrix.os }} - build_wheels_macos_arm_py38: - name: Build wheels on macOS arm - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [macos-12] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - name: Install Python - with: - python-version: '3.10' - - uses: dtolnay/rust-toolchain@stable - with: - components: llvm-tools-preview - - name: Build wheels - uses: pypa/cibuildwheel@v2.19.2 - env: - CIBW_BEFORE_ALL: rustup target add aarch64-apple-darwin - CIBW_BUILD: cp38-macosx_universal2 cp38-macosx_arm64 - CIBW_ARCHS_MACOS: arm64 universal2 - CIBW_ENVIRONMENT: >- - CARGO_BUILD_TARGET="aarch64-apple-darwin" - PYO3_CROSS_LIB_DIR="/Library/Frameworks/Python.framework/Versions/$(python -c 'import sys; print(str(sys.version_info[0])+"."+str(sys.version_info[1]))')/lib/python$(python -c 'import sys; print(str(sys.version_info[0])+"."+str(sys.version_info[1]))')" - - uses: actions/upload-artifact@v4 - with: - path: ./wheelhouse/*.whl - name: wheels-${{ matrix.os }}-arm build_wheels_32bit: name: Build wheels 32bit runs-on: ${{ matrix.os }} @@ -100,7 +71,7 @@ jobs: environment: release permissions: id-token: write - needs: ["build_wheels", "build_wheels_32bit", "build_wheels_macos_arm_py38"] + needs: ["build_wheels", "build_wheels_32bit"] steps: - uses: actions/download-artifact@v4 with: diff --git a/Cargo.toml b/Cargo.toml index 2f5fd8ce077b..15f34603c61e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ rayon = "1.10" # distributions). We only activate that feature when building the C extension module; we still need # it disabled for Rust-only tests to avoid linker errors with it not being loaded. See # https://pyo3.rs/main/features#extension-module for more. -pyo3 = { version = "0.21.2", features = ["abi3-py38"] } +pyo3 = { version = "0.21.2", features = ["abi3-py39"] } # These are our own crates. qiskit-accelerate = { path = "crates/accelerate" } diff --git a/asv.conf.json b/asv.conf.json index 70dd3b760e2c..a75bc0c59c3a 100644 --- a/asv.conf.json +++ b/asv.conf.json @@ -17,7 +17,7 @@ "dvcs": "git", "environment_type": "virtualenv", "show_commit_url": "http://github.com/Qiskit/qiskit/commit/", - "pythons": ["3.8", "3.9", "3.10", "3.11", "3.12"], + "pythons": ["3.9", "3.10", "3.11", "3.12"], "benchmark_dir": "test/benchmarks", "env_dir": ".asv/env", "results_dir": ".asv/results" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c3154abf412c..49df19808498 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,12 +37,12 @@ parameters: - name: "supportedPythonVersions" displayName: "All supported versions of Python" type: object - default: ["3.8", "3.9", "3.10", "3.11", "3.12"] + default: ["3.9", "3.10", "3.11", "3.12"] - name: "minimumPythonVersion" displayName: "Minimum supported version of Python" type: string - default: "3.8" + default: "3.9" - name: "maximumPythonVersion" displayName: "Maximum supported version of Python" diff --git a/pyproject.toml b/pyproject.toml index 9a16fc6e0ac3..689bf473e2f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "qiskit" description = "An open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives." -requires-python = ">=3.8" +requires-python = ">=3.9" license = {text = "Apache 2.0"} authors = [ { name = "Qiskit Development Team", email = "qiskit@us.ibm.com" }, @@ -27,7 +27,6 @@ classifiers = [ "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -140,12 +139,12 @@ include = ["qiskit", "qiskit.*"] [tool.black] line-length = 100 -target-version = ['py38', 'py39', 'py310', 'py311'] +target-version = ['py39', 'py310', 'py311'] [tool.cibuildwheel] manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" -skip = "pp* cp36-* cp37-* *musllinux* *win32 *i686 cp38-macosx_arm64" +skip = "pp* cp36-* cp37-* cp38-* *musllinux* *win32 *i686 cp38-macosx_arm64" test-skip = "*win32 *linux_i686" test-command = "python {project}/examples/python/stochastic_swap.py" # We need to use pre-built versions of Numpy and Scipy in the tests; they have a @@ -197,7 +196,7 @@ extension-pkg-allow-list = [ "tweedledum", ] load-plugins = ["pylint.extensions.docparams", "pylint.extensions.docstyle"] -py-version = "3.8" # update it when bumping minimum supported python version +py-version = "3.9" # update it when bumping minimum supported python version [tool.pylint.basic] good-names = ["a", "b", "i", "j", "k", "d", "n", "m", "ex", "v", "w", "x", "y", "z", "Run", "_", "logger", "q", "c", "r", "qr", "cr", "qc", "nd", "pi", "op", "b", "ar", "br", "p", "cp", "ax", "dt", "__unittest", "iSwapGate", "mu"] diff --git a/qiskit/__init__.py b/qiskit/__init__.py index 41f9d9eba1b9..25137d7a5918 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -43,14 +43,6 @@ " Qiskit unfortunately cannot enforce this requirement during environment resolution." " See https://qisk.it/packaging-1-0 for more detail." ) -if sys.version_info < (3, 9): - warnings.warn( - "Using Qiskit with Python 3.8 is deprecated as of the 1.1.0 release. " - "Support for running Qiskit with Python 3.8 will be removed in the " - "1.3.0 release, which coincides with when Python 3.8 goes end of life.", - DeprecationWarning, - ) - from . import _accelerate import qiskit._numpy_compat diff --git a/releasenotes/notes/py3.9-min-now-c9781484a0eb288e.yaml b/releasenotes/notes/py3.9-min-now-c9781484a0eb288e.yaml new file mode 100644 index 000000000000..a58dc69f9e4a --- /dev/null +++ b/releasenotes/notes/py3.9-min-now-c9781484a0eb288e.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + The minimum supported version of Python is now 3.9, this has been raised + from the previous minimum support version of 3.8. This change was necessary + because the upstream cPython project no longer supports Python 3.8. diff --git a/test/python/circuit/test_circuit_load_from_qpy.py b/test/python/circuit/test_circuit_load_from_qpy.py index 04e71a0dd4d7..db8663ace558 100644 --- a/test/python/circuit/test_circuit_load_from_qpy.py +++ b/test/python/circuit/test_circuit_load_from_qpy.py @@ -1948,8 +1948,11 @@ def test_pre_v12_rejects_standalone_var(self, version): """Test that dumping to older QPY versions rejects standalone vars.""" a = expr.Var.new("a", types.Bool()) qc = QuantumCircuit(inputs=[a]) - with io.BytesIO() as fptr, self.assertRaisesRegex( - UnsupportedFeatureForVersion, "version 12 is required.*realtime variables" + with ( + io.BytesIO() as fptr, + self.assertRaisesRegex( + UnsupportedFeatureForVersion, "version 12 is required.*realtime variables" + ), ): dump(qc, fptr, version=version) @@ -1959,8 +1962,9 @@ def test_pre_v12_rejects_index(self, version): # Be sure to use a register, since standalone vars would be rejected for other reasons. qc = QuantumCircuit(ClassicalRegister(2, "cr")) qc.store(expr.index(qc.cregs[0], 0), False) - with io.BytesIO() as fptr, self.assertRaisesRegex( - UnsupportedFeatureForVersion, "version 12 is required.*Index" + with ( + io.BytesIO() as fptr, + self.assertRaisesRegex(UnsupportedFeatureForVersion, "version 12 is required.*Index"), ): dump(qc, fptr, version=version) diff --git a/test/python/circuit/test_control_flow_builders.py b/test/python/circuit/test_control_flow_builders.py index e41b5c1f9f31..7a3a0873ae77 100644 --- a/test/python/circuit/test_control_flow_builders.py +++ b/test/python/circuit/test_control_flow_builders.py @@ -3464,9 +3464,12 @@ def test_switch_rejects_entering_case_after_close(self): def test_switch_rejects_reentering_case(self): """It shouldn't be possible to enter a case within another case.""" circuit = QuantumCircuit(1, 1) - with circuit.switch(0) as case, case(0), self.assertRaisesRegex( - CircuitError, r"Cannot enter more than one case at once" - ), case(1): + with ( + circuit.switch(0) as case, + case(0), + self.assertRaisesRegex(CircuitError, r"Cannot enter more than one case at once"), + case(1), + ): pass @ddt.data("1", 1.0, None, (1, 2)) diff --git a/test/qpy_compat/process_version.sh b/test/qpy_compat/process_version.sh index 56743c613316..3fc34557b69e 100755 --- a/test/qpy_compat/process_version.sh +++ b/test/qpy_compat/process_version.sh @@ -45,9 +45,9 @@ if [[ ! -d qpy_$version ]] ; then echo "Building venv for qiskit-terra $version" python -m venv $version if [[ ${parts[0]} -eq 0 ]] ; then - ./$version/bin/pip install "qiskit-terra==$version" + ./$version/bin/pip install -c qpy_test_constraints.txt "qiskit-terra==$version" else - ./$version/bin/pip install "qiskit==$version" + ./$version/bin/pip install -c qpy_test_constraints.txt "qiskit==$version" fi mkdir qpy_$version pushd qpy_$version diff --git a/test/qpy_compat/qpy_test_constraints.txt b/test/qpy_compat/qpy_test_constraints.txt new file mode 100644 index 000000000000..03f798b3c01a --- /dev/null +++ b/test/qpy_compat/qpy_test_constraints.txt @@ -0,0 +1,2 @@ +numpy===1.24.4 +scipy===1.10.1 diff --git a/test/qpy_compat/run_tests.sh b/test/qpy_compat/run_tests.sh index 4fc6bc5b91fd..3810773ec0f3 100755 --- a/test/qpy_compat/run_tests.sh +++ b/test/qpy_compat/run_tests.sh @@ -20,7 +20,7 @@ export PYTHONHASHSEED=$(python -S -c "import random; print(random.randint(1, 429 echo "PYTHONHASHSEED=$PYTHONHASHSEED" python -m venv qiskit_venv -qiskit_venv/bin/pip install ../.. +qiskit_venv/bin/pip install -c ../../constraints.txt ../.. parallel bash ./process_version.sh ::: `git tag --sort=-creatordate` diff --git a/test/visual/mpl/graph/references/bloch_multivector.png b/test/visual/mpl/graph/references/bloch_multivector.png index 896e513ef36849c1bf2e483f725f160286449bc9..e3036bc2ccb918533b669e8f748f3af8ca68a976 100644 GIT binary patch literal 75579 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%0Ac7eZvl86StXLN*ja4%U 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

    2mE<@@emB@Wn}I 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 P1O8~J=qOhyT7~`}YPOq@ diff --git a/test/visual/mpl/graph/references/bloch_multivector_figsize_improvements.png b/test/visual/mpl/graph/references/bloch_multivector_figsize_improvements.png index 5f5ba75d9428d1940aa8f3157c4aa819e3ef9841..c5a082e8039ac95dccbc6267a837c57cb562e87e 100644 GIT binary patch literal 73633 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%0D`c3BHc@b8BDg?66Qu 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 uhW|wW`xE{w{{O@N&zJT8?MvQ2CG5M;|WB}i6L zQOT)LVk<%cMUYS+q2P|C-RIo%zTf@*{W<;M@u;wC@3rQdbIdWu+_z7vDlS{HVF`so zS*EOXRGmUuAV;CF@h)0`zj1q&rib4o9OQKzH0&-oTrsgfPf;;(xM*$XU~O@h*Xg|d zWeYo7Q6UMTy}NnM9ULxRmJ}AY`PVlH+1Z;3Z&qddf{QG^sHA(DLRn!#e$7dcjklo8 zp-_~M9@2CU?`w5&KI7OrJKOl^Q6HoHoJC%aL+p+0lja-GEnKzo=p6Y|>rNF}-;r|V zYwlb&_vyD4^VY<^+`MJ~E}y>RR}b&B2~6t=O;s7c@Lc@SxxJS?Jl}2#6nk_cK>0$~ z_lcK6LZgbk+oCoJHtd+|aN8GFB<3sQvQ?3UAX6uYdia`3dD;-)4Pt z?xKJGA%klP??3T%{|*h#hJk_+)%D(+OGGqvb=NcMl${3)M(#7+WhTA{ zDz+Hv>RPmV&?Bzg|2ZLl~z)0i)CyIQabr(}O-ook_VjnS2%aAu_2fCN4-r&%znYQJ@<%XsUR z^PJv$MMbl$8q-XqmU~@ASU)y05I*NRL$}ZU?v(G?_pG!x)GDn;->z^iqwd~Dvq+aX z=D~X#_p81(7NNz@+vxW72FK`|rNTRQ?zH&KR@$G_p7#CwIqBKy5!asB5O1aqZp}5% zuyLHZb+<^%%xJuVly_zN#YDJ7D>pDSKba<$m4!8->F~S!=vc*qV=k?Q^m6a z%C2Ky%$PNbJj=b?5?BPXYX7*(IHS81GgS z5c-klQ}q750;|tVHjuy7p-x3>ACKzxNav@O2Rhi5Yi)8`_w|*sRm&n_E#T+lJ93#` znKcu(-!8IJX3DzNbC#u-ZT%=9FmS7K)xnXwv{ZeLju-dto!k*4JNS4+9ann%PPdSkf}xf>Qh;nhQ0ms zB}KpgQ_Dw?#XeX+@n4m!r4N7e2*3|K5mc7q`fAa%j_F-pd z=VaIZ;>7i$7j&j1kXD$@?K4hFKDjsbJ4!_E+FEJ1I5rxzu2bxrPEWpCey!PMw(?I+ zBSW`-adNaah+ep>uAw1*>Dy5Qr!VJSXIbNX)Q7=A0@}TKjI_GGFE4@u15Nt}YmW;z zEEO&g`HRKus`8w9!T+(xq4%4Q@co}2K|w)eTg4oEHDlxB%R22X${+5@>wfApNiB59 z!*X{zNN&CTjhjN*S2Hr1l$NG?rPVQ{t0F8uJbY7USC{3`w|9DZ4n38{t;7BchOS*jsM9=TnW5y^dh)?2r3{m5YUzFnq?er&Nimg6eZEHhDni?!NTFN1$ zX=|HSTUX~eTBFENl%4dqw6eO%dNv-+6Y0{mo^i$h!GoBVmNQ&3?m7|@5_{RB^=+5Z zeT=4`vX}VP_4Ms;XVQbT4QmEk^S6G?+cr4ezHH+@^UhB}tbu5{I4f9C-=SpLe)FbG zi(_hP+NVzWSIW-13+iX5G_$5Xin*zyr`B?C2*}DB_4M>ec0Dv5t&5t`^e8T_>S%SL zN6_{N2neiQG;g%}$cjWfjEjp40_26E5v#Crs;-eSkd&MjV8Tf=O-f4Y72oc-E+nSS zXf?H`#j`4O6SufF<=d!ARf$ehPKYuB!g zzBf|NKOR2{54S$Hms9~p`(WX?A>#m#`;SAPsk;sG z>YK*y?Qat)9*q@dPW;@a8g3pO5)ua7S0z0j{>b0IhMv7bcKTveX*hBibBfxZ)mYxw z*C#W6xmJ1mBS%Na!T~y}Tz0lT3Co--RKeCurChDHKHtZ`j8xGQ<0CCukyCXpvuVX4 zX@{TqxpdsyKjw1gW{F9g+hF0U!V7wOdgUnM&)ZAwXC~-jOeT{R>2_fCc2%*hk4CyG ze16Ix;hy;1c!z%^F3fiCktZjMr$S{ti$1Mg5IR$$(FQ)gbyu6RJSNPj%VGVqXzbP0wqYiuY;_O%bUg9M{|9#MQJp-fle}{17lEYX%|S z*ife?%jIMgQ2yr4;Stt&`wF)e1I!8pz!HaS$31?PE_6k=;dxM(C@M)smW9*9WqCbuVGocJY?`xsQeITn7E!0}e^zvJ%SQ=i_NaO46;F2xGkcTMEt$Oy zu87Iekm6~14g&{&_L7sQPY21cdeqA3Bg>ji2YS^!Cj*~g*R&k3*kssiu-KHs%kzQ=bXiS&=R{Yhz(cnrCA}fpkW5-Z8;AIVdBJ1qCCDKSt z8>F04JVv8=dOAalmgh$Sy;Zq)iP9uRqJF;JK8n?6;2c)>HY790i)Rfu&Ro3855#C# zi(js9yFV%gg@h#M<>>`vIuCujH84WHDa63((Q+P{6jT7llbhVNch(AIx=+}%P!)no zJN)^jr+<{7GUZRUwg+rI&hJ>T?n>Y1Jqe{~Ccmj&zWjnfXs!bn}a6Nj7uojMoPPlW~Eb8 zt4!x#J0xgWphGIw%tV!^C4h%su6=AIbxfB!64tKi>Y9hcJ{pwnE-#>!((TCeJN4;MhXbP?@Jq8s>j<7U_hisg z>ky#lfgpOcizkC*rhgns)p>UKN;@?NVRSw;&bDAk!3Ic&90Y(hJp)e`lQ!7>$Skr3 zPX>UD75*#Q5u#mu=Qx~Ta=J0wxhmOH|qsiKkQLK^$IY%m{EU%K>+-vUW`^80q# z#NgoIj44LBa=<7}-)`CDCCaTob+nBsZ;O?r_(CFK(% z^sua~EJf?7a?vWCW-48(y@&ZQBHDj6YLzaJ=k(C3=FH4Yo#+7mN93^M{&sNj`nR-c zWJ=0qTYov5cSZ=GccGj!IXN!*+QJo~FU+b2#`1gm#YX@`>K{l-D!jQ@KZTgL?Wd#s zUoNJ%hou!am-2WPwD+&zK4@O3XjTSSS>Y!kS61IqEAVR{7HRWBFx zlse6btD;7#e8;o#@)cwkN(Nqx6g+?NqN3#Hit*f5fa?>=T`wwG= zQ+(4tGq#_RO)`ebcpdYSLVzb$m^?|*%p^n6T3cJ&Ogd-&{P~44@6%jP1x#GynSR_j z;`-fRF~vp|t-N8*dh3NsF*#S(RxI~ROYczRc8O`U@%V9#XEe;D3`>)lDF*C=QW92C zQBgQxh48unxWzQ&zI$@VImd!1hg#)Tt@PnC;T-!Gv|G+^`(GPZ7xXfvC9rtAO zux4WpmGbCwEzv%6>D{W!2~JMe#rEy%#iragk6OBJcQx0QmP>DoH+ny@L(QbkwikOA z2MZbO%4w#)%?>$ZfBXHtjoX!3m9x8)XGdgbP45Zy?gFA$lbMKNN=<>VSY$~VLCS=H)G1e!lDLy!<%S&{qy+{0~$S>lr)Fwq0-|49#hTj%XcbJ^$15(o-7Oh#gZp>8%48>3@`XJhl zi8O*K9r<}sBSz>|gUry=0k%aG7Z~)SG+57X__2?>V<|<`DcWvvs3LkGqV?E#?tZ(%b1;$jP#KDnrA<9 zidm_RHl*?geO@%g8$mm2E{LqLyQG>(bPYFWYqABCy*Q| z7fo$cRU?T!Yv8;QxAR|fvNAJwpwl4B4-DqoYTH%*C=Y09tFm3ekoT@#yB4^&xsCPJ zfRfoN9~_9DVzgdEO*tSfw`&6_l8V+H7Y~evwNJnQbdqdZ!{&ytm>B-#{K)WmZ`aLV zNnv|#{pGps(o~5ERbc&|I|6AZ9UZgo+_^*g7hR6s2IAu4JxJey_0JaRdUDi6*mR%= z0hBrY+2-2o$4-N7sc4PNOT3rSJSQe50wm+KHw@e;l@z8eE2&18Qz%|Pe{>3a=2kW58TuG{OmtEWUvT4C z(5n2;_#ESs59)8uvFdn#kLF0FXQstja1V73w-vgjUR5%SaMVg?dnRc>Wj3&c#tyE; zDU*-N5!B24Fey=+czEIDXSd039K{JSF)p9^O%=C z8>??WWppeWm%NyJCU3GgxnzKmOOFiXCncJ;#+=$SEhN|b@K2Y=3qk`8oxjevx7M0{($spPy3Z@+JXqy^$%FGkS61p7^I30IoqTrJnxcO2$E(XnMkd)GZrj&l!ei$4YQ<-MI5oQ>G!HCWNi9ac+Z2ei<4c? zYIHQmPzeMNGxj~`FW>H0y-8M&yEmPmPoex_gbaGRyTwT0cV@vMkRCH^MrJD{qXEakAQ}xYQ?%!^2A9G<>{!~@f`2AyGiS6pdf`Wrq zuTIu{Wf zf|$0C2LBUf-M^?*yClssSjinq;`sOwWeOJ&P;#UUFD040CiMZ0{ zqV*&?8EIz4*hyy4uHTwA{0rZ3yTD45C z*QK@IkyqKX?)x!+gQfCkd8=wJN{>ZuS>G?@xZASL#X~w@Zsx~LS)Imv{=2QYDv``m zEwU#!?AWGE*hQo~Q?BCTfo^|Ss#8Nd%Qje~Ulo?`iRzNK|^vDS#+ z>!unnniOG1S+H$7e*?w!!-o$Uceo-{B|6tonaM^CH#iIvw2i2z386pmvSWEGb-cAT zo1wQRmr2tvN%O7Ns5+&HV|`^X0Dc8ua}s?|e9{-dtb&33t9grvSG_D#O-ggN`hv z4fjjAd-S*n!4@yW+{r=@M8jv85muNM${t}bx_aA*YGekfgi=}$DD(Uc8#iucU6JgZ z>HC{}PiKhm?s2S8);4eqDw=8?RB&%sx)UnB3^7;|74$(_&Uz?yqgR3wc+set(d`wH z()tMUTGV<`lJ-LP*@R}PG>%=2uX8!Nd8>MJwoM&`f}M$`g8oJ81_H$rEN(2YEWOV~ zdvlTP*_A;mWR5Jyw%c-bn zW{CmAq2Kk^xfmDz#>0G@H~3O_q=9TDpR8qI5HT||Ud%vcBXqo#%8HHm-c>Dpp5Rh7 z^-h1zx%MI|n8piHIi;qm0p7tud0k%ULYQA(^T|gB9)41tL61=m+@>q5I6Tu+ehknZ zMBEA~rAxfU^h(pfztgGZ@W==gO{xwcX%5Ig2S#d+lYr`Ooea6TsMue5rl*Ih<%ZT82J0b!^Oug}e1lo~s1aWURlL1AJSwugr6g z$o+PPn!d8t*?*;^>{bq_qA$%ipg;8~RK`AmXV%oxiVFz%1NV2sU||fSW3UHpe2#|) zgrt1Iw*8y(7Ti>#J?P0i`|eIg&ceBKtgcpodfp)}o>gTd#r8bL_A(Q)=_tMW$&n_c z5dNO0K0-^RPM>=`U5%6M$Wf<1lhRH8noSQ{O%N^*QQcg#D+T z)Ha!L3FQqsTD|4U>a+8`F6vs~$hm@dpfjkQ?qB=|(hvkJh)($X^EsOsFa_r&EWM;m}6<1cl*SMD{x zGLZK;vb3YdB0geUVl*qa_+o8HTK|i$3dt!t&(2nt-qIA|tVdgppcbmux6PFYyP^Ae zwg@~C0}N6CKZ&gSVXMp|-rTE&EL4w1R49?p+&hf!C?eTBuvK?t`Aty}>&oEh1EK#+ zwhZ`sPMdyag+mAkh=KTHwc*dU-9|+R`z{f+tn>SKrQV0fbBk}Rx!DWK^hKP)B8~&D zy95O4z!Fu{`-#xg%V2C}jpz21-Q@Auk!Z^DO`8uz+iT{it3i8p^<&ZpVHMFDGM2vI z-{yP-3qZAL;%Gn33DcbSUvLPvBzF(Rz z-x*bFJG;i(*yB?LtzR!fM-U3&2T`P-{^DzWt~r(L5bfMV>!3#?-DcUcWm<;iWo1kA zja|)D17g4s9(8x8)cn$PV&md^(Y6QG*C@Dxm3GQ!ft|>V+n5JxA^#rtUjfqjZlM?;)u4rY3N6~njn_FwwI}W4FIF9ZzW}}f^mIQ>y zc5Qk2cdMFF7<++>TtBnUoj>1$ASjBtpX(!xPxSEN70^zrCp~*c^XOKnc7!;Mxw=*^ z=KjuQt{azW>FOp9QU~1vB-gDd`0Bm!%|QIf%lL5nW5qtFaPl02&{nG$F`?IXg8>3= zAD?oZ=nNT`%4z@^hy9*6F5Y-1T8{VP+kN2pa%c!bc&F(ie%pysRPHvFA_?KLHS)~-4#UZLE~_vbz8U^wO4~y#d3Ugg^7hSB#X3amV3z!2Q+lL z4A(OtrA*A0ce|FS(dQa}Ct9Lo_%jJ9YGR;qYw!J$;x}E^Zxo?2_x8zkV z-X8w=`SZOMQL;vmPci_o6Y={=vTpZfXPm7Jn_(dk?>ks(MN4_6pkZMDaqBe?b_&JV z!T!LeJP=-6l}U^F?VS(vv#D={Vf--kxO@jCD&3`zD+)|cY36%5r{Ef-e=v7Rv<;LSP1ur zy-hyQM|zNIX<%&RSD;sc)idO45@j`%S(BKMNhi#D zZpl-Fdx3BlK0T})vmBqV^q3@F!7lNNtEb#Ufq2aQTPJU&}bG&SWw3|3(mXGyc5*ixL5Qoc#_ z!ilJHWo6|(pd2rapkc_ENqzeC+b!1U6}JPZ&HDob0>HVwy}i2P%P#3-1N|h_6#{sw#*>qh=Hg4Ja~ESk{jh4 zZC^gAVjbADd<6QYPq%noQgs;RLY%(Q5qBcwGVVOOkHJ%Bs;-qjUqS2Pjlg6IhgDA#>)VOg)ltx<^$iKQ}r z?ecbch9$@MdV(Kjcjl3HtdImv^WJM<3fVHcxnppb-bB2H=R_7KGmp?ey)!F$7?KKvInJX+PDDHFT4i@8)s99)3 zLxYL0zPkEZn^_P;7nFSGysEANFR60|Rt@wj(frC)va4vTSWAMi4;Rjs*y1LK- zR*K|=1f`ujcOFw#J_TW%L?@xo8j(O^A)kD`#i~M>5=IM}5S4^%VqzltnCj7zyBrBraID!^P0w(}DV1ukjfedcP3N7~J>lGd=L39FJBi$t+ z^LNAVQ}a~b=Rruw_K>pJ(NPD~8+p{GG$M@He9m|sy3a}k_m*07O%3*%^g8L$F7h){ zg9XvpBh8LdUu|MZS+ays5xt<)>Y$8l8WV4AYqP!Q1+pjEn<1W5@1nJMr)_v7?ZTN9fjDaiL7tLek@p{wP^t^)X;8R_YXltvI!)G-BO?6fD_s zS2U&Pnq;G`PY?kM2T&4I-lZA{HTrSLw&&PIiQhPBV)7(w`MH=%>G3m+DtAWZDC@x z5ov|y@alN*?o(P?!NjCu(OMcZ zLVDDXvphLfX zGC1bG&_ktoE;LJ#a9uDz7y;QM7{w>NtBgi0-xJpFi=dX z5q*Sc-ltrPZV9%sIZqk!vaCe@9_07+{^IAkUAs5; z10$kzYb{*zi%X<M<&wTULRhbr2;z}cZ2U69j#Ndf|j>r!L<_C6iC`q122z&zf?cU zNX8A^y$c*V9tr*6)ayG(BDfQf`ETJ@r#dv-fSMeFq9SIPAO%u-%$ z1C8CcYJFDeJNOrGX%iNf&-dWdUm{a8*YcaTFbxovj?ewVPzNNW#^>kD@>tE_Zj!Ol z2Nlfbv8PW@Pj61Y%6Z#mq>Hq}B_5k7Y)9rGvhW{&K^1l2@?Q2M@Rj9(tV$rgIb2$g z9z6;@aOo-W_z~eZRNBocMNM1?jI{ai_m6pCAegXp3e)1*D6cX^PSlB+QvdjMLGnK} zZ?|;+^N0Vsr2p$B|F41mzf%KV|0D#;|DWeUn+$v?_{i}-hB_x8A)yOl|5JJS0~5|? zGJ@m|_Z^*qm3i;q3C;Kl+T?%J^f*2)c6Nfv$O=Pyg4 zbju;7diz_1B7M>(nGA80H}g~?59-EQKx`r@RVGReq==;Z&y2l$_kyo}5EX^g><)an zQi*)@(Yw=gC~{ZU$We?RX6EErLEUNsxFTlPKmVLNf9{+chc`=Xnl94Z9W+vobU*2uq9k$<|8Q^Z^`^_sFu$LcWq) zBPJ%+4Tv~Evu_K_&d%Pv&@U1;2pEA;p?SWG_JpA7RH zS((;Zu>Y!@+-u{DIwf)Vb)_4AcBB^fPZht`3o1GKi-Vb^)vneS%sY)@-}D8 zj9#Ui=pS=p1nR_KGd~Sa$ov5CuK>p|#*v3c903pV`H?%mL^kr(EAqgHZe?~B#QQJj zm3FLTYZ3R`1UE5U$*l_J|7^S0fkRkcu2_7^MFgC2p#?R^C`A*bnf{@0I zVxM3(gTHBOdSfyqML4&1N=Q7C19YL>6(P@ggcS8HVh@8yBEJcGjh+jQgVT7eg1bx< zl-LIm5rX(Z1RVAlwA0+h_&JfgA9%j6puDOk_qvFke5UgXUg<}1iCtY68fY{Uwm1P0 zE3{Qr?*ktpW`!|c5>mF7p#hncVts9z-2TypSfxd#34(O#tel+W!a`}2x&Q2Ia1~tx zW`I9mKj#0~@1)O{*w59<#Bpwiv(|$V8F%ZUiGKS%ItR?yjX^Z?pL&%;M&2enekU*FAwP>ys2PD(bbM*(>OT5AN_nFB;*CF>%onTpt8;_B*1w$`^%oai5QPwjirfRCrCfCx}W|@gdN9WCo-gI z>HQ$wldWyGf;p1d@&5jP(!LNyePpE5DZkTxD4rbcA>ZjeVkG>Ge|wQ55D)lo(>g{T||EbFR%p;tW4<3S7#WTTOTWGmfy-8n_I8%evH| zfW)A4H3n<~a&-ZD!j+ESS4{DFV!-AxW$r85iMo177g-)G*Lz%2TB2r^kj;Yh^z}`t zmf6Ok7gE%oX#c-LY?rVw$-WOFBZbl%t?pGHQ&HJUHq^NK15b$$Hk5M*7SS5#*8t)` zBgP1bLtyQ?b=ceW-m7vrDml6TcjS?K#|CAcFIxxm^$r1n<2X$y0>8&+_Wnx5t2TQ+ zUXAncjUz9Vgz&j|PMXcUm7KrA5FeJ5k#RE4;?v+ba>YLD&yUeoV$z_D z!Q2H8lVQ5HP>9d3?c(#3UAY|BJWJrEeoty=OOJz7^S0nQ*L@m)LJWq={vbFw?&;Gl zzw_CIy9_uei^epAzw=oGZD7dxyZw;a8Z3brpQo`1_DjV6=l6NW8>w00<8K%39xW9i z(YOO-3ZY(htf_^qpmSsbIXU^xoh7(1vI>rCOG^vi8zC%ZpU?DF^Ua==S3gj6UafnB z%N(V=mP2KN{|Ktdam)c|?pUL4Y8s8WUcTu70U~80?5JCvbUK*_0g;E)^-RVQS7T=z zUWn|*MtO>7^tyf_G!BeiEU`;|v2R;FXWo&{iw6*l(U_%CR!2!gF~e1foeISs{#Fzx z9llJQfro$MYP_%gWmhi6S>Zg0ZT>?m2I>0UUN6}G!+w;!8})>H3%7wUJQiAC6jUr3 z@+5IFfvbBqSNYJPt1t(G^ks>%9|5^WYbl7c0A^7^#>8(8ATZ#6ds<$80yT{+AF?XGZ5}#NFHSzs zw;YkBGpH|*rO4yHH`cFo+v3F=3_m`IFidrw*3sF4lrlbrXWSlD6_2cukd+17ur958 zcY32hNSQn@o|N;@_Z6S#Ot8H&C&J=k&SPaRc8hp#ao{8%*@0VxfiB=zz9Xd$hk@)7 z5GIL?>%k}%W$&Uc;*P!^p7Aok?cCkx?mFj|RgJmC;K#2QkM{I=b>s1X3JAsdbEpG^ zbv>q(nwkh@N|-AkNEkjgJP8U5llneRD&7YkPAX!xkF5L4hOAEa%5Vu7OHS15U4&0S zbBv9B|ILyoSQnrf%WrRQBab|xaxAmZlP;0EVx@uVO+#sDMa&fIY- zbI~q0y>qk+Ar=vliX!lTh1gi%muT>rsAT^NG3Qp)s_Q@lu8K1hzi#Z{ErF66gsIQU zH>%;P@ql&s0-X5`y%4AW9|@0a9mQYP>nd(VNeqzl?L7cX5Tl2nL!Yvf7~DmUx6J>H zD%d^$-oxQx`&9iLRpb;DWZI(C`g%>nFdXlCoXI07=YEUGjV&!9=Z7ytL=Ra9PR75F z-ml=QSi%qI*(uP+;QR9bRYEhwhZnA-VtIycVbLGfvJ#Zr{7ft+T3$(Ot; z?*B8YEG$qoQi0Gjtr~^U1OUQ-4$ZgR)izXBpb8u}tKU_Xl;*k0kTJ0v@BkBB2SPfhS-LNJ8v@?@&h(tOJi`mU z{L#|9x^+h$5bEx$JKT|qZkG>iLc64S;X)h+s}dlO#l>v{PV9x)+*Cx($7o!0KY;vY zd;9Mf51gg;-eQADzia2tnxxao(9U|YSr)p-R6)~sA%zrqx34al`;igVvW`hP8yc6EKOl+F zMaW>-$Y`=YUgmtOA*KgMDy7uG#{0JqHo{4efN`ln3^w}qy5OeRCfGQ+KJawk{(E1n zzs2HA+$=dnndAM)g!6Bz9pDcI0If)h97xJvSV2_ug+4F5NB4cI7PGe!=g2CFO7NB` zFd-?|LNRR&hg zJ`6e;yQ12TBSsB~tD2uU;-t{ASbI;;c`Sf81G6)$HPS(t-;~DQ?}F{i{ri_RHcQ_pQ_hyU$;Z5qnK+8(keE+@n1#CdVT-|4Db@a+V0@y z{;s+951=Gyfy?H%AhWNks>}0PnD|UZAcC~8fPD`}xh|#fZD2Y4WGU?HCfKeWno&A| zTz^!)ASe8ad^g3r^nUAR*6^T;rOnb&*L;%${Mu<_V#>m)0fuLEx5s~ZJk<7BH9Rm@ z!&msE<+0M(+a+I5A|(-zF-DnjJ17>=AG8QtexFMUSa7WpBr^irZnXk z=sYmk-2kg`Cjilqb4oB1l6uj_j9f4Y3_8>ZkDRJcpL&@^6tB0aqauIcNG+S-+k@s@ z#Qb*c?;7#P*DLq@hv@s~>S@)Ad}kd9SGEjMY+j+%+z#L9q)eP)+iA}cN_QHYT{Vt$OZWOzh=9hWUwbK8;vJ+Soz-VM?B8dUe?t}&J@3x_; zO54(M*H!-4h;m)ooUANnJ{5EK=|DbjWrs`u0zByE^SrD2-S_QL36X=^aN`#D(rN7H_tOu$uky~%VQHW z^>(E$-?=71%NFJVHC5XB?cc3>f8HNE`wO?GJU02AvR3K+8x*9<1%!meqi1gOSsZ6| z+y%q_#m!e*;~3OAlp&w#JHEip|YymS}zo>uKDhq2Wk-I(Kbn{PAArs`!|g1hh}!PmoCfJb-|RfHpXeCRg7u zz0p$lO75A(6YKYf-h~W`K2b~sz-c_6+Gw*yH*+OrrT%x{*XT8$9ht$#E1o4T|1Gy$ z?Az*;7Oboj!+S)8U?0^xI4$Leid*6l zDHqeWYgup4{tf3s{e_)m)Hf;X4rg8HY29n_C9Y)epKho9xT>dnEF`T?J!z5P8cBz= z4%~)Gl0;-hV|3A_&xi#cq;2ylOeeWx0tcTJ0xCeVDBQx_+^>pW zhuNJhM}`)fWVj4aZ%O9_m2_Uf4)Q7whshosKu!xLT&A0zRS^9ZLz>B%nVOzJn4=gJ z(xr!AR?V>?h5`t`N&#?*IW(NsUN)Y{MpZEHFg78*)O2)N8Gz~iAk?^&k=@;};jIj6zC)83;$WH+oe_w6T9 z`1ORkoS{vtunpBfZ*tf$Hb2y%Ugze8`!;nkZ)O*`{R_b+^7%Qaay>(7#1yzP8fkzI zjIn6LCIQ7lp*4gJ(7h3F&uH&&$LOIIYZ_DPdeJId@#criC;6g5j&ZwuUqwchEp2Rm z%}5No)1@TgegFk9ik0ccD-wd*2SZFa3BnGFjFkDgZ~^7ku3s@raf39WzvtTYs`UVK zXCLxCTf*UW-IxwKn|Mqy9;E~bf9i`7fEyu7!3$vw>~Ym9D-E49pe+Mkw$F0v=(IDl|JieG+uJYKlG zE@h`gp{-eH9Ke#e<5B1X7<(Wu`1yw{%j&0F#pB?q!=C8)wplGyOd0%f>x^K)DxHW( zOlccjdbbv&;2?7h`HR)7U0e%?&c-1$5#AgVrawOLcv1U5KRW`>7q2Dgy`n!{>gg|A z%`vqsnIf{o3GLd>P(H$UB1llO9a}DyzO#NC3bqifBfj{N1$8+NkxFD`#aJ~mUc1F7 z@`Q%#bi2)@vxaGk+SarKfwhhY9;Ar})rNj@x-qxmlZqWJ{Nql^j<@bA+|5IeEI7T% zi62ITN-k!!+!`a^D75J6G8N2;rm%JEyRob1UK%)my+Phf#O?9Zq!90M!BC(&=r7FA zI-oV{e!tPK9!?8WYAD5Pme-S=dx9+^2gqp1?Z)&fDI}gl3m1ue0+H03e+8$Yo(2>} z-ua=2mnhlWyYjr_TKt=;MQmHVzq=l0gR{jPD@!EiCd(So2T{5}A!}_+E$x6AY0^u` zi}UJv*;Jc2kI76U@u^T#>aNA5>|#5FlTVj!3W|Hdu{PmV7;VZa?u*T(8oWdb9SoX5 z5Qv0vw$EJzNlbr>r=Kj+zq5XhZBWVAYWR@63jl89aHC0%+2Mm=#EHx2JrJYi%wNb( zoA12>Q`iU=oOF}$?pg^|I%6n24#pb`xG?vs)P)w0|MmJBq3+45UP;I80#c(Tzb zsi+{s`{Rt~2@2``7AQ!||65msUVw5G{mo}H#f#;SNBO?uvFDSMJ1px;(fBXneU;Gg z#hx2TU0Pz4q3`OrKinZ8$D~OIkiKl&z+ys`-pv~`JhQp&>uaW4UYELH;7ektbg<6ktFN- z+}QYSEVE`l4i1}Nv;x>@oS)w!-fzA?S~6-Mg~E3gQW1C$|Mef%=&;GpyfS}lwA%Q= z`cy>5GN;jMbatd~R>7gdY+X*p4t^viz&E`2DEhwSv8!^gEd5)vZNeJ1G_O~}Shp$l z)2#pw?M%kR_{OLEwu|3CcOZN(mu-Jih*PRxq`qM?zqt9?tBLO}zhK^;KXFX8chMSv zD`aehdOa+ugl4O+=f_a~y0Xr{e|ocKUeLQrQ^7UX8cEToG~RPcS{SCOhBJcd zzD$`N{mtrTB@m&KIsY(yx^TD163Q)(@4mCpnAj)SqQ5|F2GmVnyn5T)NzD&D8S@bf zJ8HlR!dM;syt5#gSkN&Rc6)~x-U^U_niOYYiGKt1;2FKNTHMP4eK~pU1_)5Z2hNT} zM5XQ04QNZ>Pl~PbF0QC=^&GMqJhV>ASMiBc@!o(?F`ICWcy4;lGtn06f@xzB^Bev+ zbwnYTkofXzDcujjue5kr@yahiX`HDGOb%HWIERO!Au)G??Y8+SGh%M^2_P^eXAFqB zX=aCypW{?GsxgCk%9G?>FOgDRg?-KgK*<0rNzg6{CPXWR)YbID%ondRc#0>o9U0$- ztTmZA#FM|`QQly>ilwcE4>R%cisjl#dgYp_?ORjZ&+n=)I{sxR+@v+JqN*PnN0nzI z=Dz810J}oI#8mLI535WJWW+1`E8b=e6 z1XU~diZo9@}S?g|{X|}}`{tpuKvQG%MZz(L!mA7n9pYGdN5f+^E zVjagW;T+Q?i~a{Unw6cMl$)!IF0`JENTkE0D*5&L>R+!t^ ziN^CDUQklVI3%CjKlv%wB~&JN(B(a-JtBxn!&OLTipXn0EM{j|#2-5fPN;cZlm=*i z#hF{|6QpblZ}qxYZO@(CreI98Q6ys+kCWn5BP6Y> z4Ct3uv#y9f9NGUbJpkMUs4OC_Ko5Xaq(*if@&!>YJ?-r6heg6!-4{RG^$rwgcFWlu zPf?rC_f}-nUM}5Ty5mnStX+FU(Ca75gG@tx5=gJdbRdYzEb5dKfXmit`f3X4RJSP3 za7qp@RPZ_aXs*>`&_-)Xpj6w-h#0W_uZC!9=FQ5Qf9p)A=+$NFo*Y%tf#vZVuknbdV7{0ee7|Ta(+%>Vs@~kvbw9@&l(@_ zZzm?8`iS7X`^kQT`Zk1a?8|eu>(f_tzV4c@WSkkkBGQBtPuz%3k({@RaEZEL4$j*` z(B%JaL14ZhoQj;ffq|g1VtKn%Q#)JLZmULyz()ROZyU|O$+|0%&o%z5xGsXJP3f^d zw2;E9{wrDXFBo3(g%4L4zNgkr@I#nFSxQM(1GcF2?cP5&t$e9 zeFgD7K3)JM3S`Oc=2&T| z;E(KCSEk1AE?UZa-HAd-!)uD5;}EKM45Z}#S@$7`zkFNZIVkyY46dfc zwq!Rw~T@@6x^%%%<-;1VgR5>shj_s?2~!;@hSL5mPZ&|d}5ygUiNgSz6%Tk$nVI6a^@ zZrE=dPF}ErM2545yuc;tpoGbAzp~EWeV%s5j{Ow&HSHI+TQFJ~>a7#CKtU&?@U&ZY zacb~;D$6!3XqAV<1}RlqyG6V|rh^%x%KQ!t-E9!{0}=9J&D?PtzH73m)*lAZb_H=)EW zTAH~p=>j8c$xjAfQ(F(atmR#}vLG1{3&`kJ|B;0XT6Fq#uHP{yqjL2C(KSJGLp!^} z+`07uUIR&95E6>F_F*=``kDtZ2PY9%Pa{=NXDp$L`g#Cv7)FXN{BL4hESAQh6YpfAfcH| zMM^@5QsyCqOqntdnSJ}9`@Y}r`~SbSzO}CPJiYgOKV9c_9>?(;_TImJlz;M`c`#Uh{4m-^T+v~nTXk%M<0xMuWV{!0{mO*O9VL- z(y3aN_FHNuX;M}&T?Bl-@#p}_T{s~6$OEK0DabjXUEfEP z~mXO2bNijFO*R^iz!4TW7` zaaqKKqmVsy+<=scMhs8CBw4 zeudi}Rw3zf;uu{-V~YclB6}D~09&9gouWn-<_1kZ8$#0xM%veqF_7>~25d@7LMJ}Z zvN3c0S3&h;6!o4w*!8*2L>|u5A9A4V>b;v0mvrHfSV&R|DnhS4j)$h$$1n! zH2Tj=XsF`=Yhr_J-L}ot_Yp({EJ1M%et|0)3`YmgTxClBKKZQjmqS(mO9#<1`BAab z`^&HJ;CHWu3Q<&T;Van-R7MzT{f7$r`2^oLu`R`!SPlUS@tguXhciKxG-Oz#>iNE{ zu02(%S3?DT1UaFuK=21%B;z%6j!-eOvM&Gwg7>K$84xh~T%u@pFD^X0+sDn}{H|O# z@BQOkx(gvOr%Pp_3SmFsJ$dXeq?PUke-=1NpWpv#nnw^@kow?`97Y6Z8~NyL*i&|4 z%6;{4>ml0kn6~Y_JYa!=E0T7(SV42wL7ftjY(HPlJI4`)gO*pc$JaCspS2G3GiX@9 z&zy=PGF-SfLb;W-w581Dn*a=%3^4Cp!-}(3f#`}!AKR50NMVPRtpcR!IN3bO3#dSc z%}8srT_6BREjfbSE-x}N&K1Sc1N`#K?eeT+WIkY@6Z7ag^V-K&5b9p^qoSkPXy@=p zoO^KBn%{L14$bTM66WN3ruCeO=(0R?Apl;XM^*zqzoDO?GL_Z@WCx_xSi?%t*uGmM zLmx}{$P2(3G{0T$tmK06N}}cZTYhY@itBkwc^^4j(l&b zH(*;bv63lO&Leiqw{VvJ!!O@?-V3yzmpnKxJT|is2+h^o!(yO-dQH4wL672SqbDR4 zjGqp~n<9KEUW{}RU8y4rtH5+nHAjl90uFh)Lv!Mb7aNFb6Sasz!?rVnYk;9!^*I`|*F3*ug*q2gy1hfedHLV*{OQL;#`cj0$}5{#;pVxq zP<$d#k7Cmg5}6}P8vJ9D@?ff6!@Aw^rw{o`Vn4-=JaYqkvA0tHoLdw%lvl>!E10jr z@6DdnOZN6irELF{E$QiYWV-F^*DF19O9X?r#ZbNHT^6LS`?-7P&i;&Z%opodGEY>` zMf(NYZq8DBZ^t^3cB0|luz-?WLZR-?SQ=W2*6QIx6b(Lu*yC<)>8O3Sx({2SZ>+AZ zjmI8WINMLS1DG|JpPFTRS4tns!X`L1AwnISaH4n;GhSe49vMd)sSQnDfRg-1LthR4 z;Wh~_JzBQ>d*eb0?){D#?K+?L8}8KJ%bNa1?0b{+5zgMA{4iPXERwl=Yd%>h8*K(H z$-T8mKppS|eMz^AiM{_q27FRn4|oKUUp&}LKOH>bsqF7z>oSw55VRx^GGc=fGVrE> z%#(i;Su_zTd|AT?S24x%)?l8!!aFr}Q3!`$3Pjdh&xV(Xy{bQ?EW&BR^T+%j&*yi&2lC1(MC(JluuR&PEopqs&`|FOtPi2OZcn;b5o~+Wwp_n=&wix_V!=ez z_{YS3=DOIxEJz|dae(gr)%AcCC1#Kfef%|Tb!%yJl+UGMNBrSg9eoz>klMG;)`Ev;2eyhVo->Fxk9gq%!6W*I1#su7 zdJu~(d}JU;$6<=u^3eat)0{Qlf;T}XsB08YmJzBL6W~M{0JU($#me9EvD6{)o&m$j z7IN)7^>4+$8B?#H-K?Gc465(xKxS@+wnj@~4DyW$9@6Dy`GrOs{QP?{9fmi0|2)@!0gX z!uAO8#ulD-qHW_6oPn)l7T;jO35|fi;;V2TVD|$!6uC}%SUabNvwNu zKasyTXy$~fE8>IU`G=aMv8u@nvh?7ebtT;|)R*9MSbN>8s;j$U<6get4FUUE5Q`8i zS7R145w5cO(3)S^A9`kD&|<=R=r!By92m&6`CZ9=^Ej z?7QsjUI4TOZzobIbn5`{986o=pnkf2 zp8@i(b1ZS|uT%DPMDzyH&R4FgNC_;mIja2V?QoKqXsMx0 zx#k64&JJY>AvsFqdnJg-5EZ+@h1V1*MJz1Dg1@29{98v7+aT0%FUQnTU%$4<3ly$l z4LQ(qM(Vdb9p@xCt6g!O_m-H4qwIz=^lNxF0Qu_$mZj5GPMgB^Z>87`V}kwq`uYib zLMVP2D>m8tFkj5O^T_H%~hn&B^7OXh;Ol^8Y(=FRi zrJJO8_-$1QJVW(yfmQ>nD$)%r-b!#x_KoR)?>xs}MOVYPGl`T&P)Ws*y#dcY)EI`iU-N__=AVo7*MO)hlJ>RXovZv}F5oucFqdgZ|S2TXqehT25cvDAINq?M# zvaR}I=oom$L(0v>oinfw>bhBY2KSFCQP>>*2I@C|Cmsml11j7Vmg(exkByBXF;~OK z{pnb5Z9KGG*w0RXKD=J6doGb5cU@-NHZmeypLsTkOpgOpgnxF%bQ^amVNozX)j)E7UqH^}W} z$k_AI4O!9DMULqYm8XBdswu_stc6WJ@rLD$>GO#8wXv~D_UfOBP2P6I!T#h)-l`Oe zc?Np6P$ESG%8J`2h

    sB6{xW(&pRmJVewLONDL_Kd;VU0ASa){i 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 GtN#yV2F`{6 literal 108666 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%0DgS7BW=#Lf(cg>`CeU3KwYX1&evbD+8Pw)w^^ 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 Date: Wed, 11 Sep 2024 13:55:41 +0200 Subject: [PATCH 69/85] Fix an edge case in Sabre's release valve (#13114) * Fix edge case in Sabre release valve If a Sabre trial does not find a set of Swaps to route nodes, the "release valve" adds Swaps to route the two-qubit gate in between the the closest two qubits. In rare cases, this leads to _more_ than one gate being routable, which was not handled correctly previously. Co-authored-by: Jake Lishman * add reno and test * Use sensible syntax Co-authored-by: Kevin Hartman * Use sensible grammar Co-authored-by: Kevin Hartman * clippy * Check if the new test breaks CI * Revert "Check if the new test breaks CI" This reverts commit 01bcdc7ca225220e7f5a319e2ef52f626251610a. --------- Co-authored-by: Jake Lishman Co-authored-by: Kevin Hartman --- crates/accelerate/src/sabre/layer.rs | 5 ++- crates/accelerate/src/sabre/route.rs | 34 ++++++++++++++++--- ...x-sabre-releasevalve-7f9af9bfc0482e04.yaml | 7 ++++ test/python/transpiler/test_sabre_layout.py | 25 ++++++++++++-- 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/fix-sabre-releasevalve-7f9af9bfc0482e04.yaml diff --git a/crates/accelerate/src/sabre/layer.rs b/crates/accelerate/src/sabre/layer.rs index 899321a96681..dec8253ad282 100644 --- a/crates/accelerate/src/sabre/layer.rs +++ b/crates/accelerate/src/sabre/layer.rs @@ -70,7 +70,10 @@ impl FrontLayer { pub fn remove(&mut self, index: &NodeIndex) { // The actual order in the indexmap doesn't matter as long as it's reproducible. // Swap-remove is more efficient than a full shift-remove. - let [a, b] = self.nodes.swap_remove(index).unwrap(); + let [a, b] = self + .nodes + .swap_remove(index) + .expect("Tried removing index that does not exist."); self.qubits[a.index()] = None; self.qubits[b.index()] = None; } diff --git a/crates/accelerate/src/sabre/route.rs b/crates/accelerate/src/sabre/route.rs index bef6d501b4aa..0fd594993943 100644 --- a/crates/accelerate/src/sabre/route.rs +++ b/crates/accelerate/src/sabre/route.rs @@ -27,6 +27,7 @@ use rustworkx_core::petgraph::prelude::*; use rustworkx_core::petgraph::visit::EdgeRef; use rustworkx_core::shortest_path::dijkstra; use rustworkx_core::token_swapper::token_swapper; +use smallvec::{smallvec, SmallVec}; use crate::getenv_use_multiple_threads; use crate::nlayout::{NLayout, PhysicalQubit}; @@ -286,7 +287,7 @@ impl<'a, 'b> RoutingState<'a, 'b> { fn force_enable_closest_node( &mut self, current_swaps: &mut Vec<[PhysicalQubit; 2]>, - ) -> NodeIndex { + ) -> SmallVec<[NodeIndex; 2]> { let (&closest_node, &qubits) = { let dist = &self.target.distance; self.front_layer @@ -328,7 +329,32 @@ impl<'a, 'b> RoutingState<'a, 'b> { current_swaps.push([shortest_path[end], shortest_path[end - 1]]); } current_swaps.iter().for_each(|&swap| self.apply_swap(swap)); - closest_node + + // If we apply a single swap it could be that we route 2 nodes; that is a setup like + // A - B - A - B + // and we swap the middle two qubits. This cannot happen if we apply 2 or more swaps. + if current_swaps.len() > 1 { + smallvec![closest_node] + } else { + // check if the closest node has neighbors that are now routable -- for that we get + // the other physical qubit that was swapped and check whether the node on it + // is now routable + let mut possible_other_qubit = current_swaps[0] + .iter() + // check if other nodes are in the front layer that are connected by this swap + .filter_map(|&swap_qubit| self.front_layer.qubits()[swap_qubit.index()]) + // remove the closest_node, which we know we already routed + .filter(|(node_index, _other_qubit)| *node_index != closest_node) + .map(|(_node_index, other_qubit)| other_qubit); + + // if there is indeed another candidate, check if that gate is routable + if let Some(other_qubit) = possible_other_qubit.next() { + if let Some(also_routed) = self.routable_node_on_qubit(other_qubit) { + return smallvec![closest_node, also_routed]; + } + } + smallvec![closest_node] + } } /// Return the swap of two virtual qubits that produces the best score of all possible swaps. @@ -573,14 +599,14 @@ pub fn swap_map_trial( } if routable_nodes.is_empty() { // If we exceeded the max number of heuristic-chosen swaps without making progress, - // unwind to the last progress point and greedily swap to bring a ndoe together. + // unwind to the last progress point and greedily swap to bring a node together. // Efficiency doesn't matter much; this path never gets taken unless we're unlucky. current_swaps .drain(..) .rev() .for_each(|swap| state.apply_swap(swap)); let force_routed = state.force_enable_closest_node(&mut current_swaps); - routable_nodes.push(force_routed); + routable_nodes.extend(force_routed); } state.update_route(&routable_nodes, current_swaps); if state.heuristic.decay.is_some() { diff --git a/releasenotes/notes/fix-sabre-releasevalve-7f9af9bfc0482e04.yaml b/releasenotes/notes/fix-sabre-releasevalve-7f9af9bfc0482e04.yaml new file mode 100644 index 000000000000..17432259be29 --- /dev/null +++ b/releasenotes/notes/fix-sabre-releasevalve-7f9af9bfc0482e04.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixed an edge case in :class:`.SabreLayout`, where in rare cases on large + devices and challenging circuits, the routing would fail. This was due to the + release valve making more than one two-qubit gate routable, where only one was expected. + Fixed `#13081 `__. \ No newline at end of file diff --git a/test/python/transpiler/test_sabre_layout.py b/test/python/transpiler/test_sabre_layout.py index a5ebef43540f..7565ee17655f 100644 --- a/test/python/transpiler/test_sabre_layout.py +++ b/test/python/transpiler/test_sabre_layout.py @@ -18,16 +18,16 @@ from qiskit import QuantumRegister, QuantumCircuit from qiskit.circuit.classical import expr, types -from qiskit.circuit.library import EfficientSU2 +from qiskit.circuit.library import EfficientSU2, QuantumVolume from qiskit.transpiler import CouplingMap, AnalysisPass, PassManager -from qiskit.transpiler.passes import SabreLayout, DenseLayout, StochasticSwap +from qiskit.transpiler.passes import SabreLayout, DenseLayout, StochasticSwap, Unroll3qOrMore from qiskit.transpiler.exceptions import TranspilerError from qiskit.converters import circuit_to_dag from qiskit.compiler.transpiler import transpile from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.transpiler.passes.layout.sabre_pre_layout import SabrePreLayout from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager -from test import QiskitTestCase # pylint: disable=wrong-import-order +from test import QiskitTestCase, slow_test # pylint: disable=wrong-import-order from ..legacy_cmaps import ALMADEN_CMAP, MUMBAI_CMAP @@ -315,6 +315,25 @@ def test_support_var_with_explicit_routing_pass(self): layout = pass_.property_set["layout"] self.assertEqual([layout[q] for q in qc.qubits], [2, 3, 4, 1, 5]) + @slow_test + def test_release_valve_routes_multiple(self): + """Test Sabre works if the release valve routes more than 1 operation. + + Regression test of #13081. + """ + qv = QuantumVolume(500, seed=42) + qv.measure_all() + qc = Unroll3qOrMore()(qv) + + cmap = CouplingMap.from_heavy_hex(21) + pm = PassManager( + [ + SabreLayout(cmap, swap_trials=20, layout_trials=20, max_iterations=4, seed=100), + ] + ) + _ = pm.run(qc) + self.assertIsNotNone(pm.property_set.get("layout")) + class DensePartialSabreTrial(AnalysisPass): """Pass to run dense layout as a sabre trial.""" From 117974066f69de67c1e05408ec5febafd267c8c4 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 11 Sep 2024 08:39:44 -0400 Subject: [PATCH 70/85] Prepare 1.3.0b1 release (#13125) * Prepare 1.3.0b1 release This commit changes the version strings from 1.3.0 to 1.3.0b1 in preparation for tagging the 1.3.0b1 pre-release. After we publish the 1.3.0b1 tag we should switch the version number back to 1.3.0 to continue developing the 1.3.0 release series as we approach the actual release. * Also skip 3.8 builds on 32 bit platforms In the recently merged #12910 the minimum Python version was raised to 3.9. As part of this the cibuildwheel config was updated to skip 38 uilds since they wont work anymore. However that PR missed that there was an additional skip config in for the 32 bit builds in the job definition. This commit adds the missing skip so the 32bit wheel builds will work as well. --- .github/workflows/wheels.yml | 2 +- docs/conf.py | 2 +- qiskit/VERSION.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 3314bae05d5b..d3cb464bf8cc 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -60,7 +60,7 @@ jobs: - name: Build wheels uses: pypa/cibuildwheel@v2.19.2 env: - CIBW_SKIP: 'pp* cp36-* cp37-* *musllinux* *amd64 *x86_64' + CIBW_SKIP: 'pp* cp36-* cp37-* cp38-* *musllinux* *amd64 *x86_64' - uses: actions/upload-artifact@v4 with: path: ./wheelhouse/*.whl diff --git a/docs/conf.py b/docs/conf.py index 1ebd77749b41..277276df42a4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,7 +32,7 @@ # The short X.Y version version = "1.3" # The full version, including alpha/beta/rc tags -release = "1.3.0" +release = "1.3.0b1" language = "en" diff --git a/qiskit/VERSION.txt b/qiskit/VERSION.txt index f0bb29e76388..94bfba8ed4ed 100644 --- a/qiskit/VERSION.txt +++ b/qiskit/VERSION.txt @@ -1 +1 @@ -1.3.0 +1.3.0b1 From c5e9f8ae9eff14a62604c933cd288a8ca57226f8 Mon Sep 17 00:00:00 2001 From: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:37:41 -0400 Subject: [PATCH 71/85] Remove Pulse library URL renaming in docs (#13107) --- docs/conf.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 277276df42a4..493dd58de83c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -114,23 +114,6 @@ autosummary_generate = True autosummary_generate_overwrite = False -# The pulse library contains some names that differ only in capitalization, during the changeover -# surrounding SymbolPulse. Since these resolve to autosummary filenames that also differ only in -# capitalization, this causes problems when the documentation is built on an OS/filesystem that is -# enforcing case-insensitive semantics. This setting defines some custom names to prevent the clash -# from happening. -autosummary_filename_map = { - "qiskit.pulse.library.Constant": "qiskit.pulse.library.Constant_class.rst", - "qiskit.pulse.library.Sawtooth": "qiskit.pulse.library.Sawtooth_class.rst", - "qiskit.pulse.library.Triangle": "qiskit.pulse.library.Triangle_class.rst", - "qiskit.pulse.library.Cos": "qiskit.pulse.library.Cos_class.rst", - "qiskit.pulse.library.Sin": "qiskit.pulse.library.Sin_class.rst", - "qiskit.pulse.library.Gaussian": "qiskit.pulse.library.Gaussian_class.rst", - "qiskit.pulse.library.Drag": "qiskit.pulse.library.Drag_class.rst", - "qiskit.pulse.library.Square": "qiskit.pulse.library.Square_fun.rst", - "qiskit.pulse.library.Sech": "qiskit.pulse.library.Sech_fun.rst", -} - # We only use Google-style docstrings, and allowing Napoleon to parse Numpy-style docstrings both # slows down the build (a little) and can sometimes result in _regular_ section headings in # module-level documentation being converted into surprising things. From 81063a79a3144eeb43bb5eaab54b46574176835c Mon Sep 17 00:00:00 2001 From: Alexander Ivrii Date: Wed, 11 Sep 2024 18:51:47 +0300 Subject: [PATCH 72/85] improved fast-path detection in HLS (#13070) * improved fast-path detection in HLS * apply Jake's code review comments * making the comment even more clearer --- .../passes/synthesis/high_level_synthesis.py | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index 73a402dc202f..31036de69645 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -280,6 +280,15 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: return self._run(dag, tracker) def _run(self, dag: DAGCircuit, tracker: QubitTracker) -> DAGCircuit: + # Check if HighLevelSynthesis can be skipped. + for node in dag.op_nodes(): + qubits = tuple(dag.find_bit(q).index for q in node.qargs) + if not self._definitely_skip_node(node, qubits, dag): + break + else: + # The for-loop terminates without reaching the break statement + return dag + # Start by analyzing the nodes in the DAG. This for-loop is a first version of a potentially # more elaborate approach to find good operation/ancilla allocations. It greedily iterates # over the nodes, checking whether we can synthesize them, while keeping track of the @@ -293,12 +302,7 @@ def _run(self, dag: DAGCircuit, tracker: QubitTracker) -> DAGCircuit: used_qubits = None # check if synthesis for the operation can be skipped - if ( - dag.has_calibration_for(node) - or len(node.qargs) < self._min_qubits - or node.is_directive() - or self._definitely_skip_node(node, qubits) - ): + if self._definitely_skip_node(node, qubits, dag): pass # next check control flow @@ -312,7 +316,7 @@ def _run(self, dag: DAGCircuit, tracker: QubitTracker) -> DAGCircuit: # now we are free to synthesize else: # this returns the synthesized operation and the qubits it acts on -- note that this - # may be different than the original qubits, since we may use auxiliary qubits + # may be different from the original qubits, since we may use auxiliary qubits synthesized, used_qubits = self._synthesize_operation(node.op, qubits, tracker) # if the synthesis changed the operation (i.e. it is not None), store the result @@ -335,7 +339,7 @@ def _run(self, dag: DAGCircuit, tracker: QubitTracker) -> DAGCircuit: if len(synthesized_nodes) == 0: return dag - # Otherwise we will rebuild with the new operations. Note that we could also + # Otherwise, we will rebuild with the new operations. Note that we could also # check if no operation changed in size and substitute in-place, but rebuilding is # generally as fast or faster, unless very few operations are changed. out = dag.copy_empty_like() @@ -631,19 +635,32 @@ def _apply_annotations( return synthesized - def _definitely_skip_node(self, node: DAGOpNode, qubits: tuple[int] | None) -> bool: + def _definitely_skip_node( + self, node: DAGOpNode, qubits: tuple[int] | None, dag: DAGCircuit + ) -> bool: """Fast-path determination of whether a node can certainly be skipped (i.e. nothing will attempt to synthesise it) without accessing its Python-space `Operation`. This is tightly coupled to `_recursively_handle_op`; it exists as a temporary measure to avoid Python-space `Operation` creation from a `DAGOpNode` if we wouldn't do anything to the node (which is _most_ nodes).""" + + if ( + dag.has_calibration_for(node) + or len(node.qargs) < self._min_qubits + or node.is_directive() + ): + return True + return ( # The fast path is just for Rust-space standard gates (which excludes # `AnnotatedOperation`). node.is_standard_gate() - # If it's a controlled gate, we might choose to do funny things to it. - and not node.is_controlled_gate() + # We don't have the fast-path for controlled gates over 3 or more qubits. + # However, we most probably want the fast-path for controlled 2-qubit gates + # (such as CX, CZ, CY, CH, CRX, and so on), so "_definitely_skip_node" should + # not immediately return False when encountering a controlled gate over 2 qubits. + and not (node.is_controlled_gate() and node.num_qubits >= 3) # If there are plugins to try, they need to be tried. and not self._methods_to_try(node.name) # If all the above constraints hold, and it's already supported or the basis translator From 7e0e0e73c8077ce253f357b663359f287f335852 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 11 Sep 2024 17:04:17 -0400 Subject: [PATCH 73/85] Fix ABI3 issues identified during 1.3.0b1 release attempt (#13136) We recently tried to publish the 1.3.0b1 release unsucessfully. During the wheel build jobs abi3audit was failing because it correctly identified a couple of abi violations in the builds. The first was we were tagging the package incorrectly as being with a minimum level of Python 3.8 instead of the correct minimum of 3.9. This commit updates the setup.py tag to match the package metadata with the binary. The second issue is we were creating `PyInit_*` symbols for submodules which goes against the abi3 naming recomendations and abi3 audit flags it as a violation. We had this issue previously in 1.2.0 but was fixed for that release. However since 1.2.0 and now several stray usages of `#[pymodule]` on submodules slipped in during development. This commit fixes those so the bad symbol names won't be created anymore. Once this commit merges we should tag the new commit as 1.3.0b1. Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> --- crates/accelerate/src/circuit_library/mod.rs | 1 - crates/accelerate/src/commutation_analysis.rs | 3 +-- crates/accelerate/src/commutation_cancellation.rs | 3 +-- crates/accelerate/src/commutation_checker.rs | 1 - crates/accelerate/src/gate_direction.rs | 1 - crates/accelerate/src/remove_diagonal_gates_before_measure.rs | 1 - setup.py | 2 +- 7 files changed, 3 insertions(+), 9 deletions(-) diff --git a/crates/accelerate/src/circuit_library/mod.rs b/crates/accelerate/src/circuit_library/mod.rs index d0444c484dc8..9df16a04fc6c 100644 --- a/crates/accelerate/src/circuit_library/mod.rs +++ b/crates/accelerate/src/circuit_library/mod.rs @@ -14,7 +14,6 @@ use pyo3::prelude::*; mod entanglement; -#[pymodule] pub fn circuit_library(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(entanglement::get_entangler_map))?; Ok(()) diff --git a/crates/accelerate/src/commutation_analysis.rs b/crates/accelerate/src/commutation_analysis.rs index 2da8cfce931e..0a9a2304df54 100644 --- a/crates/accelerate/src/commutation_analysis.rs +++ b/crates/accelerate/src/commutation_analysis.rs @@ -12,7 +12,7 @@ use pyo3::exceptions::PyValueError; use pyo3::prelude::PyModule; -use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyResult, Python}; +use pyo3::{pyfunction, wrap_pyfunction, Bound, PyResult, Python}; use qiskit_circuit::Qubit; use crate::commutation_checker::CommutationChecker; @@ -185,7 +185,6 @@ pub(crate) fn analyze_commutations( Ok(out_dict.unbind()) } -#[pymodule] pub fn commutation_analysis(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(analyze_commutations))?; Ok(()) diff --git a/crates/accelerate/src/commutation_cancellation.rs b/crates/accelerate/src/commutation_cancellation.rs index dc2d4436d83a..7ae7d3d7ce1a 100644 --- a/crates/accelerate/src/commutation_cancellation.rs +++ b/crates/accelerate/src/commutation_cancellation.rs @@ -15,7 +15,7 @@ use std::f64::consts::PI; use hashbrown::{HashMap, HashSet}; use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; -use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyResult, Python}; +use pyo3::{pyfunction, wrap_pyfunction, Bound, PyResult, Python}; use rustworkx_core::petgraph::stable_graph::NodeIndex; use smallvec::{smallvec, SmallVec}; @@ -273,7 +273,6 @@ pub(crate) fn cancel_commutations( Ok(()) } -#[pymodule] pub fn commutation_cancellation(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(cancel_commutations))?; Ok(()) diff --git a/crates/accelerate/src/commutation_checker.rs b/crates/accelerate/src/commutation_checker.rs index b00d7c624c92..c7fbd03a2afe 100644 --- a/crates/accelerate/src/commutation_checker.rs +++ b/crates/accelerate/src/commutation_checker.rs @@ -767,7 +767,6 @@ fn hashable_params(params: &[Param]) -> PyResult> { .collect() } -#[pymodule] pub fn commutation_checker(m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; diff --git a/crates/accelerate/src/gate_direction.rs b/crates/accelerate/src/gate_direction.rs index aee5ca097322..e7fef8456238 100644 --- a/crates/accelerate/src/gate_direction.rs +++ b/crates/accelerate/src/gate_direction.rs @@ -142,7 +142,6 @@ where Ok(true) } -#[pymodule] pub fn gate_direction(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(py_check_with_coupling_map))?; m.add_wrapped(wrap_pyfunction!(py_check_with_target))?; diff --git a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs index cf2c738f131a..e510d73666cc 100644 --- a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs +++ b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs @@ -102,7 +102,6 @@ fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { Ok(()) } -#[pymodule] pub fn remove_diagonal_gates_before_measure(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(run_remove_diagonal_before_measure))?; Ok(()) diff --git a/setup.py b/setup.py index 61168050547c..ad6d1f8ead86 100644 --- a/setup.py +++ b/setup.py @@ -51,5 +51,5 @@ features=features, ) ], - options={"bdist_wheel": {"py_limited_api": "cp38"}}, + options={"bdist_wheel": {"py_limited_api": "cp39"}}, ) From 03575e66dfcdc5e7283dfcb17f81347d74d3a3aa Mon Sep 17 00:00:00 2001 From: Kevin Hartman Date: Wed, 11 Sep 2024 18:32:49 -0400 Subject: [PATCH 74/85] Make `DAGCircuit` fields `dag`, `qubits`, and `clbits` private. (#13117) * Make DAGCircuit fields 'dag', 'qubits', and 'clbits' private. Immutable getters are added to provide the same access we were using without the risk of data incoherence. * Update commutation_cancellation.rs. --- crates/accelerate/src/check_map.rs | 2 +- crates/accelerate/src/commutation_analysis.rs | 6 +-- .../src/commutation_cancellation.rs | 6 +-- .../src/euler_one_qubit_decomposer.rs | 6 +-- crates/accelerate/src/gate_direction.rs | 2 +- crates/accelerate/src/inverse_cancellation.rs | 8 +-- .../remove_diagonal_gates_before_measure.rs | 8 +-- crates/accelerate/src/split_2q_unitaries.rs | 2 +- crates/circuit/src/dag_circuit.rs | 50 ++++++++++++++++--- crates/circuit/src/dot_utils.rs | 6 +-- 10 files changed, 66 insertions(+), 30 deletions(-) diff --git a/crates/accelerate/src/check_map.rs b/crates/accelerate/src/check_map.rs index 8ebf50cd372d..da0592093817 100644 --- a/crates/accelerate/src/check_map.rs +++ b/crates/accelerate/src/check_map.rs @@ -40,7 +40,7 @@ fn recurse<'py>( } }; for node in dag.op_nodes(false) { - if let NodeType::Operation(inst) = &dag.dag[node] { + if let NodeType::Operation(inst) = &dag.dag()[node] { let qubits = dag.get_qargs(inst.qubits); if inst.op.control_flow() { if let OperationRef::Instruction(py_inst) = inst.op.view() { diff --git a/crates/accelerate/src/commutation_analysis.rs b/crates/accelerate/src/commutation_analysis.rs index 0a9a2304df54..e8b47658b9f4 100644 --- a/crates/accelerate/src/commutation_analysis.rs +++ b/crates/accelerate/src/commutation_analysis.rs @@ -80,7 +80,7 @@ pub(crate) fn analyze_commutations_inner( // if the node is an input/output node, they do not commute, so we only // continue if the nodes are operation nodes if let (NodeType::Operation(packed_inst0), NodeType::Operation(packed_inst1)) = - (&dag.dag[current_gate_idx], &dag.dag[*prev_gate_idx]) + (&dag.dag()[current_gate_idx], &dag.dag()[*prev_gate_idx]) { let op1 = packed_inst0.op.view(); let op2 = packed_inst1.op.view(); @@ -153,7 +153,7 @@ pub(crate) fn analyze_commutations( // we know all wires are of type Wire::Qubit, since in analyze_commutations_inner // we only iterater over the qubits let py_wire = match wire { - Wire::Qubit(q) => dag.qubits.get(q).unwrap().to_object(py), + Wire::Qubit(q) => dag.qubits().get(q).unwrap().to_object(py), _ => return Err(PyValueError::new_err("Unexpected wire type.")), }; @@ -176,7 +176,7 @@ pub(crate) fn analyze_commutations( // Then we add the {(node, wire): index} dictionary for ((node_index, wire), index) in node_indices { let py_wire = match wire { - Wire::Qubit(q) => dag.qubits.get(q).unwrap().to_object(py), + Wire::Qubit(q) => dag.qubits().get(q).unwrap().to_object(py), _ => return Err(PyValueError::new_err("Unexpected wire type.")), }; out_dict.set_item((dag.get_node(py, node_index)?, py_wire), index)?; diff --git a/crates/accelerate/src/commutation_cancellation.rs b/crates/accelerate/src/commutation_cancellation.rs index 7ae7d3d7ce1a..8e4e9281e103 100644 --- a/crates/accelerate/src/commutation_cancellation.rs +++ b/crates/accelerate/src/commutation_cancellation.rs @@ -105,14 +105,14 @@ pub(crate) fn cancel_commutations( if let Some(wire_commutation_set) = commutation_set.get(&Wire::Qubit(wire)) { for (com_set_idx, com_set) in wire_commutation_set.iter().enumerate() { if let Some(&nd) = com_set.first() { - if !matches!(dag.dag[nd], NodeType::Operation(_)) { + if !matches!(dag.dag()[nd], NodeType::Operation(_)) { continue; } } else { continue; } for node in com_set.iter() { - let instr = match &dag.dag[*node] { + let instr = match &dag.dag()[*node] { NodeType::Operation(instr) => instr, _ => panic!("Unexpected type in commutation set."), }; @@ -198,7 +198,7 @@ pub(crate) fn cancel_commutations( let mut total_angle: f64 = 0.0; let mut total_phase: f64 = 0.0; for current_node in cancel_set { - let node_op = match &dag.dag[*current_node] { + let node_op = match &dag.dag()[*current_node] { NodeType::Operation(instr) => instr, _ => panic!("Unexpected type in commutation set run."), }; diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index 4c0a8539cf34..98333cad39d2 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -1086,7 +1086,7 @@ pub(crate) fn optimize_1q_gates_decomposition( Some(_) => 1., None => raw_run.len() as f64, }; - let qubit: PhysicalQubit = if let NodeType::Operation(inst) = &dag.dag[raw_run[0]] { + let qubit: PhysicalQubit = if let NodeType::Operation(inst) = &dag.dag()[raw_run[0]] { PhysicalQubit::new(dag.get_qargs(inst.qubits)[0].0) } else { unreachable!("nodes in runs will always be op nodes") @@ -1172,7 +1172,7 @@ pub(crate) fn optimize_1q_gates_decomposition( let operator = raw_run .iter() .map(|node_index| { - let node = &dag.dag[*node_index]; + let node = &dag.dag()[*node_index]; if let NodeType::Operation(inst) = node { if let Some(target) = target { error *= compute_error_term_from_target(inst.op.name(), target, qubit); @@ -1215,7 +1215,7 @@ pub(crate) fn optimize_1q_gates_decomposition( let mut outside_basis = false; if let Some(basis) = basis_gates { for node in &raw_run { - if let NodeType::Operation(inst) = &dag.dag[*node] { + if let NodeType::Operation(inst) = &dag.dag()[*node] { if !basis.contains(inst.op.name()) { outside_basis = true; break; diff --git a/crates/accelerate/src/gate_direction.rs b/crates/accelerate/src/gate_direction.rs index e7fef8456238..7c7d9d898726 100644 --- a/crates/accelerate/src/gate_direction.rs +++ b/crates/accelerate/src/gate_direction.rs @@ -89,7 +89,7 @@ where T: Fn(&PackedInstruction, &[Qubit]) -> bool, { for node in dag.op_nodes(false) { - let NodeType::Operation(packed_inst) = &dag.dag[node] else { + let NodeType::Operation(packed_inst) = &dag.dag()[node] else { panic!("PackedInstruction is expected"); }; diff --git a/crates/accelerate/src/inverse_cancellation.rs b/crates/accelerate/src/inverse_cancellation.rs index 0b3404c92ffb..1cfcc6c83214 100644 --- a/crates/accelerate/src/inverse_cancellation.rs +++ b/crates/accelerate/src/inverse_cancellation.rs @@ -65,7 +65,7 @@ fn run_on_self_inverse( let mut chunk: Vec = Vec::new(); let max_index = gate_cancel_run.len() - 1; for (i, cancel_gate) in gate_cancel_run.iter().enumerate() { - let node = &dag.dag[*cancel_gate]; + let node = &dag.dag()[*cancel_gate]; if let NodeType::Operation(inst) = node { if gate_eq(py, inst, &gate)? { chunk.push(*cancel_gate); @@ -79,7 +79,7 @@ fn run_on_self_inverse( partitions.push(std::mem::take(&mut chunk)); } else { let next_qargs = if let NodeType::Operation(next_inst) = - &dag.dag[gate_cancel_run[i + 1]] + &dag.dag()[gate_cancel_run[i + 1]] { next_inst.qubits } else { @@ -132,8 +132,8 @@ fn run_on_inverse_pairs( for nodes in runs { let mut i = 0; while i < nodes.len() - 1 { - if let NodeType::Operation(inst) = &dag.dag[nodes[i]] { - if let NodeType::Operation(next_inst) = &dag.dag[nodes[i + 1]] { + if let NodeType::Operation(inst) = &dag.dag()[nodes[i]] { + if let NodeType::Operation(next_inst) = &dag.dag()[nodes[i + 1]] { if inst.qubits == next_inst.qubits && ((gate_eq(py, inst, &gate_0)? && gate_eq(py, next_inst, &gate_1)?) || (gate_eq(py, inst, &gate_1)? diff --git a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs index e510d73666cc..5e1ba4182344 100644 --- a/crates/accelerate/src/remove_diagonal_gates_before_measure.rs +++ b/crates/accelerate/src/remove_diagonal_gates_before_measure.rs @@ -48,7 +48,7 @@ fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { let mut nodes_to_remove = Vec::new(); for index in dag.op_nodes(true) { - let node = &dag.dag[index]; + let node = &dag.dag()[index]; let NodeType::Operation(inst) = node else { panic!() }; @@ -58,7 +58,7 @@ fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { .next() .expect("index is an operation node, so it must have a predecessor."); - match &dag.dag[predecessor] { + match &dag.dag()[predecessor] { NodeType::Operation(pred_inst) => match pred_inst.standard_gate() { Some(gate) => { if DIAGONAL_1Q_GATES.contains(&gate) { @@ -69,7 +69,7 @@ fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { let successors = dag.quantum_successors(predecessor); let remove_s = successors .map(|s| { - let node_s = &dag.dag[s]; + let node_s = &dag.dag()[s]; if let NodeType::Operation(inst_s) = node_s { inst_s.op.name() == "measure" } else { @@ -94,7 +94,7 @@ fn run_remove_diagonal_before_measure(dag: &mut DAGCircuit) -> PyResult<()> { } for node_to_remove in nodes_to_remove { - if dag.dag.node_weight(node_to_remove).is_some() { + if dag.dag().node_weight(node_to_remove).is_some() { dag.remove_op_node(node_to_remove); } } diff --git a/crates/accelerate/src/split_2q_unitaries.rs b/crates/accelerate/src/split_2q_unitaries.rs index 83ab94bf301d..b7bccf44232d 100644 --- a/crates/accelerate/src/split_2q_unitaries.rs +++ b/crates/accelerate/src/split_2q_unitaries.rs @@ -28,7 +28,7 @@ pub fn split_2q_unitaries( ) -> PyResult<()> { let nodes: Vec = dag.op_nodes(false).collect(); for node in nodes { - if let NodeType::Operation(inst) = &dag.dag[node] { + if let NodeType::Operation(inst) = &dag.dag()[node] { let qubits = dag.get_qargs(inst.qubits).to_vec(); let matrix = inst.op.matrix(inst.params_view()); // We only attempt to split UnitaryGate objects, but this could be extended in future diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 197ad57278a2..d872806c5315 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -225,7 +225,7 @@ pub struct DAGCircuit { calibrations: HashMap>, - pub dag: StableDiGraph, + dag: StableDiGraph, #[pyo3(get)] qregs: Py, @@ -237,9 +237,9 @@ pub struct DAGCircuit { /// The cache used to intern instruction cargs. cargs_interner: Interner<[Clbit]>, /// Qubits registered in the circuit. - pub qubits: BitData, + qubits: BitData, /// Clbits registered in the circuit. - pub clbits: BitData, + clbits: BitData, /// Global phase. global_phase: Param, /// Duration. @@ -736,8 +736,8 @@ impl DAGCircuit { /// /// Returns: /// list(:class:`.Qubit`): The current sequence of registered qubits. - #[getter] - pub fn qubits(&self, py: Python<'_>) -> Py { + #[getter(qubits)] + pub fn py_qubits(&self, py: Python<'_>) -> Py { self.qubits.cached().clone_ref(py) } @@ -751,8 +751,8 @@ impl DAGCircuit { /// /// Returns: /// list(:class:`.Clbit`): The current sequence of registered clbits. - #[getter] - pub fn clbits(&self, py: Python<'_>) -> Py { + #[getter(clbits)] + pub fn py_clbits(&self, py: Python<'_>) -> Py { self.clbits.cached().clone_ref(py) } @@ -4985,6 +4985,42 @@ def _format(operand): } impl DAGCircuit { + /// Returns an immutable view of the inner StableGraph managed by the circuit. + #[inline(always)] + pub fn dag(&self) -> &StableDiGraph { + &self.dag + } + + /// Returns an immutable view of the Interner used for Qargs + #[inline(always)] + pub fn qargs_interner(&self) -> &Interner<[Qubit]> { + &self.qargs_interner + } + + /// Returns an immutable view of the Interner used for Cargs + #[inline(always)] + pub fn cargs_interner(&self) -> &Interner<[Clbit]> { + &self.cargs_interner + } + + /// Returns an immutable view of the Global Phase `Param` of the circuit + #[inline(always)] + pub fn global_phase(&self) -> &Param { + &self.global_phase + } + + /// Returns an immutable view of the Qubits registered in the circuit + #[inline(always)] + pub fn qubits(&self) -> &BitData { + &self.qubits + } + + /// Returns an immutable view of the Classical bits registered in the circuit + #[inline(always)] + pub fn clbits(&self) -> &BitData { + &self.clbits + } + /// Return an iterator of gate runs with non-conditional op nodes of given names pub fn collect_runs( &self, diff --git a/crates/circuit/src/dot_utils.rs b/crates/circuit/src/dot_utils.rs index f6769c6cad11..8558535788a0 100644 --- a/crates/circuit/src/dot_utils.rs +++ b/crates/circuit/src/dot_utils.rs @@ -38,7 +38,7 @@ pub fn build_dot( where T: Write, { - let graph = &dag.dag; + let graph = dag.dag(); writeln!(file, "{} {{", TYPE[graph.is_directed() as usize])?; if let Some(graph_attr_map) = graph_attrs { for (key, value) in graph_attr_map.iter() { @@ -57,8 +57,8 @@ where } for edge in graph.edge_references() { let edge_weight = match edge.weight() { - Wire::Qubit(qubit) => dag.qubits.get(*qubit).unwrap(), - Wire::Clbit(clbit) => dag.clbits.get(*clbit).unwrap(), + Wire::Qubit(qubit) => dag.qubits().get(*qubit).unwrap(), + Wire::Clbit(clbit) => dag.clbits().get(*clbit).unwrap(), Wire::Var(var) => var, }; writeln!( From 2fa6dd65d6fae28c1b0a364b8d8b068be7cc1cb1 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 12 Sep 2024 10:10:31 +0200 Subject: [PATCH 75/85] deprecate BackendV1 in `PassManagerConfig.from_backend` (#12931) * deprecate BackendV1 in PassManagerConfig.from_backend * test.python.transpiler.test_passmanager_config * primitives/test_backend_estimator_v2 * test.python.primitives.test_backend_estimator_v2.TestBackendEstimatorV2 * res --- qiskit/transpiler/passmanager_config.py | 22 ++++- .../followup_12629-8bfcf1a3d4e6cabf.yaml | 6 ++ .../primitives/test_backend_estimator_v2.py | 99 ++++++++++++++++--- .../transpiler/test_passmanager_config.py | 11 ++- 4 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 releasenotes/notes/followup_12629-8bfcf1a3d4e6cabf.yaml diff --git a/qiskit/transpiler/passmanager_config.py b/qiskit/transpiler/passmanager_config.py index 4c53bc47b31c..0ebbff430301 100644 --- a/qiskit/transpiler/passmanager_config.py +++ b/qiskit/transpiler/passmanager_config.py @@ -13,6 +13,7 @@ """Pass Manager Configuration class.""" import pprint +import warnings from qiskit.transpiler.coupling import CouplingMap from qiskit.transpiler.instruction_durations import InstructionDurations @@ -113,11 +114,17 @@ def __init__( def from_backend(cls, backend, _skip_target=False, **pass_manager_options): """Construct a configuration based on a backend and user input. - This method automatically gererates a PassManagerConfig object based on the backend's + This method automatically generates a PassManagerConfig object based on the backend's features. User options can be used to overwrite the configuration. + .. deprecated:: 1.3 + The method ``PassManagerConfig.from_backend`` will stop supporting inputs of type + :class:`.BackendV1` in the `backend` parameter in a future release no + earlier than 2.0. :class:`.BackendV1` is deprecated and implementations should move + to :class:`.BackendV2`. + Args: - backend (BackendV1): The backend that provides the configuration. + backend (BackendV1 or BackendV2): The backend that provides the configuration. pass_manager_options: User-defined option-value pairs. Returns: @@ -126,12 +133,21 @@ def from_backend(cls, backend, _skip_target=False, **pass_manager_options): Raises: AttributeError: If the backend does not support a `configuration()` method. """ - res = cls(**pass_manager_options) backend_version = getattr(backend, "version", 0) + if backend_version == 1: + warnings.warn( + "The method PassManagerConfig.from_backend will stop supporting inputs of " + f"type `BackendV1` ( {backend} ) in the `backend` parameter in a future " + "release no earlier than 2.0. `BackendV1` is deprecated and implementations " + "should move to `BackendV2`.", + category=DeprecationWarning, + stacklevel=2, + ) if not isinstance(backend_version, int): backend_version = 0 if backend_version < 2: config = backend.configuration() + res = cls(**pass_manager_options) if res.basis_gates is None: if backend_version < 2: res.basis_gates = getattr(config, "basis_gates", None) diff --git a/releasenotes/notes/followup_12629-8bfcf1a3d4e6cabf.yaml b/releasenotes/notes/followup_12629-8bfcf1a3d4e6cabf.yaml new file mode 100644 index 000000000000..227946d0dffb --- /dev/null +++ b/releasenotes/notes/followup_12629-8bfcf1a3d4e6cabf.yaml @@ -0,0 +1,6 @@ +--- +deprecations_transpiler: + - | + The method :meth:`.PassManagerConfig.from_backend` will stop supporting inputs of type + :class:`.BackendV1` in the `backend` parameter in a future release no earlier than 2.0. + :class:`.BackendV1` is deprecated and implementations should move to :class:`.BackendV2`. diff --git a/test/python/primitives/test_backend_estimator_v2.py b/test/python/primitives/test_backend_estimator_v2.py index 12a932b83819..dd55750c55a0 100644 --- a/test/python/primitives/test_backend_estimator_v2.py +++ b/test/python/primitives/test_backend_estimator_v2.py @@ -145,7 +145,10 @@ def test_estimator_run_v1(self, backend, abelian_grouping): ): pm = generate_preset_pass_manager(optimization_level=0, backend=backend) psi1, psi2 = pm.run([psi1, psi2]) - estimator = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + estimator = BackendEstimatorV2(backend=backend, options=self._options) estimator.options.abelian_grouping = abelian_grouping # Specify the circuit and observable by indices. # calculate [ ] @@ -235,7 +238,10 @@ def test_estimator_with_pub_v1(self, backend, abelian_grouping): bind2 = BindingsArray.coerce({tuple(psi2.parameters): theta2}) pub2 = EstimatorPub(psi2, obs2, bind2) - estimator = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + estimator = BackendEstimatorV2(backend=backend, options=self._options) estimator.options.abelian_grouping = abelian_grouping result4 = estimator.run([pub1, pub2]).result() np.testing.assert_allclose(result4[0].data.evs, [1.55555728, -1.08766318], rtol=self._rtol) @@ -264,7 +270,10 @@ def test_estimator_run_no_params_v1(self, backend, abelian_grouping): ): pm = generate_preset_pass_manager(optimization_level=0, backend=backend) circuit = pm.run(circuit) - est = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + est = BackendEstimatorV2(backend=backend, options=self._options) est.options.abelian_grouping = abelian_grouping observable = self.observable.apply_layout(circuit.layout) result = est.run([(circuit, observable)]).result() @@ -331,7 +340,13 @@ def test_run_single_circuit_observable(self, backend, abelian_grouping): @combine(backend=BACKENDS_V1, abelian_grouping=[True, False]) def test_run_single_circuit_observable_v1(self, backend, abelian_grouping): """Test for single circuit and single observable case.""" - est = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarnsRegex( + DeprecationWarning, + expected_regex=r"The method PassManagerConfig\.from_backend will stop supporting inputs of " + "type `BackendV1`", + ): + # BackendEstimatorV2 wont allow BackendV1 + est = BackendEstimatorV2(backend=backend, options=self._options) est.options.abelian_grouping = abelian_grouping with self.assertWarnsRegex( DeprecationWarning, @@ -438,7 +453,11 @@ def test_run_1qubit_v1(self, backend, abelian_grouping): op = SparsePauliOp.from_list([("I", 1)]) op2 = SparsePauliOp.from_list([("Z", 1)]) - est = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + est = BackendEstimatorV2(backend=backend, options=self._options) + est.options.abelian_grouping = abelian_grouping op_1 = op.apply_layout(qc.layout) result = est.run([(qc, op_1)]).result() @@ -513,7 +532,10 @@ def test_run_2qubits_v1(self, backend, abelian_grouping): op2 = SparsePauliOp.from_list([("ZI", 1)]) op3 = SparsePauliOp.from_list([("IZ", 1)]) - est = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + est = BackendEstimatorV2(backend=backend, options=self._options) est.options.abelian_grouping = abelian_grouping op_1 = op.apply_layout(qc.layout) result = est.run([(qc, op_1)]).result() @@ -539,7 +561,47 @@ def test_run_2qubits_v1(self, backend, abelian_grouping): result = est.run([(qc2, op_6)]).result() np.testing.assert_allclose(result[0].data.evs, [-1], rtol=self._rtol) - @combine(backend=BACKENDS, abelian_grouping=[True, False]) + @combine(backend=BACKENDS_V1, abelian_grouping=[True, False]) + def test_run_errors_v1(self, backend, abelian_grouping): + """Test for errors. + To be removed once BackendV1 is removed.""" + qc = QuantumCircuit(1) + qc2 = QuantumCircuit(2) + + op = SparsePauliOp.from_list([("I", 1)]) + op2 = SparsePauliOp.from_list([("II", 1)]) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + est = BackendEstimatorV2(backend=backend, options=self._options) + est.options.abelian_grouping = abelian_grouping + with self.assertRaises(ValueError): + est.run([(qc, op2)]).result() + with self.assertRaises(ValueError): + est.run([(qc, op, [[1e4]])]).result() + with self.assertRaises(ValueError): + est.run([(qc2, op2, [[1, 2]])]).result() + with self.assertRaises(ValueError): + est.run([(qc, [op, op2], [[1]])]).result() + with self.assertRaises(ValueError): + est.run([(qc, op)], precision=-1).result() + with self.assertRaises(ValueError): + est.run([(qc, 1j * op)], precision=0.1).result() + # precision == 0 + with self.assertRaises(ValueError): + est.run([(qc, op, None, 0)]).result() + with self.assertRaises(ValueError): + est.run([(qc, op)], precision=0).result() + # precision < 0 + with self.assertRaises(ValueError): + est.run([(qc, op, None, -1)]).result() + with self.assertRaises(ValueError): + est.run([(qc, op)], precision=-1).result() + with self.subTest("missing []"): + with self.assertRaisesRegex(ValueError, "An invalid Estimator pub-like was given"): + _ = est.run((qc, op)).result() + + @combine(backend=BACKENDS_V2, abelian_grouping=[True, False]) def test_run_errors(self, backend, abelian_grouping): """Test for errors""" qc = QuantumCircuit(1) @@ -624,7 +686,13 @@ def test_run_numpy_params_v1(self, backend, abelian_grouping): statevector_estimator = StatevectorEstimator(seed=123) target = statevector_estimator.run([(qc, op, params_list)]).result() - backend_estimator = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarnsRegex( + DeprecationWarning, + expected_regex=r"The method PassManagerConfig\.from_backend will stop supporting inputs of " + "type `BackendV1`", + ): + # BackendEstimatorV2 wont allow BackendV1 + backend_estimator = BackendEstimatorV2(backend=backend, options=self._options) backend_estimator.options.abelian_grouping = abelian_grouping with self.subTest("ndarrary"): @@ -662,7 +730,10 @@ def test_precision(self, backend, abelian_grouping): @combine(backend=BACKENDS_V1, abelian_grouping=[True, False]) def test_precision_v1(self, backend, abelian_grouping): """Test for precision""" - estimator = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + estimator = BackendEstimatorV2(backend=backend, options=self._options) estimator.options.abelian_grouping = abelian_grouping with self.assertWarnsRegex( DeprecationWarning, @@ -705,7 +776,10 @@ def test_diff_precision(self, backend, abelian_grouping): @combine(backend=BACKENDS_V1, abelian_grouping=[True, False]) def test_diff_precision_v1(self, backend, abelian_grouping): """Test for running different precisions at once""" - estimator = BackendEstimatorV2(backend=backend, options=self._options) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + estimator = BackendEstimatorV2(backend=backend, options=self._options) estimator.options.abelian_grouping = abelian_grouping with self.assertWarnsRegex( DeprecationWarning, @@ -792,7 +866,10 @@ def test_job_size_limit_backend_v1(self): op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)]) k = 5 param_list = self._rng.random(qc.num_parameters).tolist() - estimator = BackendEstimatorV2(backend=backend) + with self.assertWarns(DeprecationWarning): + # When BackendEstimatorV2 is called with a backend V1, it raises a + # DeprecationWarning from PassManagerConfig.from_backend + estimator = BackendEstimatorV2(backend=backend) with patch.object(backend, "run") as run_mock: estimator.run([(qc, op, param_list)] * k).result() self.assertEqual(run_mock.call_count, 10) diff --git a/test/python/transpiler/test_passmanager_config.py b/test/python/transpiler/test_passmanager_config.py index 341da357d37a..569f67738a16 100644 --- a/test/python/transpiler/test_passmanager_config.py +++ b/test/python/transpiler/test_passmanager_config.py @@ -33,7 +33,7 @@ def test_config_from_backend(self): """ with self.assertWarns(DeprecationWarning): backend = Fake27QPulseV1() - config = PassManagerConfig.from_backend(backend) + config = PassManagerConfig.from_backend(backend) self.assertEqual(config.basis_gates, backend.configuration().basis_gates) self.assertEqual(config.inst_map, backend.defaults().instruction_schedule_map) self.assertEqual( @@ -66,9 +66,9 @@ def test_from_backend_and_user_v1(self): with self.assertWarns(DeprecationWarning): backend = Fake20QV1() - config = PassManagerConfig.from_backend( - backend, basis_gates=["user_gate"], initial_layout=initial_layout - ) + config = PassManagerConfig.from_backend( + backend, basis_gates=["user_gate"], initial_layout=initial_layout + ) self.assertEqual(config.basis_gates, ["user_gate"]) self.assertNotEqual(config.basis_gates, backend.configuration().basis_gates) self.assertIsNone(config.inst_map) @@ -107,7 +107,8 @@ def test_from_backendv1_inst_map_is_none(self): with self.assertWarns(DeprecationWarning): backend = Fake27QPulseV1() backend.defaults = lambda: None - config = PassManagerConfig.from_backend(backend) + with self.assertWarns(DeprecationWarning): + config = PassManagerConfig.from_backend(backend) self.assertIsInstance(config, PassManagerConfig) self.assertIsNone(config.inst_map) From 118a16c0bccc932dac4cc3e545fa358d3e5ad8cf Mon Sep 17 00:00:00 2001 From: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Date: Thu, 12 Sep 2024 04:17:37 -0400 Subject: [PATCH 76/85] Use new URL for link in circuit docs page (#13135) Co-authored-by: Luciano Bello --- qiskit/circuit/quantumcircuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 566a6fef9f70..780efba5faf1 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -2108,7 +2108,7 @@ def tensor(self, other: "QuantumCircuit", inplace: bool = False) -> Optional["Qu Remember that in the little-endian convention the leftmost operation will be at the bottom of the circuit. See also - `the docs `__ + `the docs `__ for more information. .. parsed-literal:: From 1ff6361303c4b4bd472eee5249fadcbace40ca96 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Thu, 12 Sep 2024 15:07:26 +0200 Subject: [PATCH 77/85] Oxidize `PauliFeatureMap` (#13045) * port PauliFeatureMap to Rust * more docs, less error expecting * cleanup, docstrings * clippy & speedup * base for dictionary entanglement * rm unnecessary pub * add reno * refactor ``rmultiply_param`` * fix & test dict entanglement * clippy * Refactor Rust code a bit - improve readability - only create barrier if necessary * RIP iterators (for proper error handling) performance seems to be unaffected :) --- .../src/circuit_library/entanglement.rs | 50 ++- crates/accelerate/src/circuit_library/mod.rs | 2 + .../src/circuit_library/pauli_feature_map.rs | 346 +++++++++++++++++ crates/circuit/src/imports.rs | 1 + crates/circuit/src/operations.rs | 22 +- qiskit/circuit/library/__init__.py | 3 + .../library/data_preparation/__init__.py | 9 +- .../{z_feature_map.py => _z_feature_map.py} | 77 ++-- .../{zz_feature_map.py => _zz_feature_map.py} | 35 +- .../data_preparation/pauli_feature_map.py | 359 ++++++++++++++++-- .../notes/rust-paulifm-1dc7b1c2dc756614.yaml | 16 + .../circuit/library/test_pauli_feature_map.py | 295 +++++++++++++- 12 files changed, 1119 insertions(+), 96 deletions(-) create mode 100644 crates/accelerate/src/circuit_library/pauli_feature_map.rs rename qiskit/circuit/library/data_preparation/{z_feature_map.py => _z_feature_map.py} (52%) rename qiskit/circuit/library/data_preparation/{zz_feature_map.py => _zz_feature_map.py} (71%) create mode 100644 releasenotes/notes/rust-paulifm-1dc7b1c2dc756614.yaml diff --git a/crates/accelerate/src/circuit_library/entanglement.rs b/crates/accelerate/src/circuit_library/entanglement.rs index db602ef717fa..fbfb5c0193f1 100644 --- a/crates/accelerate/src/circuit_library/entanglement.rs +++ b/crates/accelerate/src/circuit_library/entanglement.rs @@ -12,6 +12,7 @@ use itertools::Itertools; use pyo3::prelude::*; +use pyo3::types::PyDict; use pyo3::{ types::{PyAnyMethods, PyInt, PyList, PyListMethods, PyString, PyTuple}, Bound, PyAny, PyResult, @@ -173,30 +174,45 @@ pub fn get_entanglement<'a>( return Ok(Box::new( get_entanglement_from_str(num_qubits, block_size, as_str.as_str(), offset)?.map(Ok), )); + } else if let Ok(dict) = entanglement.downcast::() { + if let Some(value) = dict.get_item(block_size)? { + let list = value.downcast::()?; + return _check_entanglement_list(list.to_owned(), block_size); + } else { + return Ok(Box::new(std::iter::empty())); + } } else if let Ok(list) = entanglement.downcast::() { - let entanglement_iter = list.iter().map(move |el| { - let connections = el - .downcast::()? - // .expect("Entanglement must be list of tuples") // clearer error message than `?` - .iter() - .map(|index| index.downcast::()?.extract()) - .collect::, _>>()?; - - if connections.len() != block_size as usize { - return Err(QiskitError::new_err(format!( - "Entanglement {:?} does not match block size {}", - connections, block_size - ))); - } - Ok(connections) - }); - return Ok(Box::new(entanglement_iter)); + return _check_entanglement_list(list.to_owned(), block_size); } Err(QiskitError::new_err( "Entanglement must be a string or list of qubit indices.", )) } +fn _check_entanglement_list<'a>( + list: Bound<'a, PyList>, + block_size: u32, +) -> PyResult>> + 'a>> { + let entanglement_iter = list.iter().map(move |el| { + let connections = el + .downcast::()? + // .expect("Entanglement must be list of tuples") // clearer error message than `?` + .iter() + .map(|index| index.downcast::()?.extract()) + .collect::, _>>()?; + + if connections.len() != block_size as usize { + return Err(QiskitError::new_err(format!( + "Entanglement {:?} does not match block size {}", + connections, block_size + ))); + } + + Ok(connections) + }); + Ok(Box::new(entanglement_iter)) +} + /// Get the entanglement for given number of qubits and block size. /// /// Args: diff --git a/crates/accelerate/src/circuit_library/mod.rs b/crates/accelerate/src/circuit_library/mod.rs index 9df16a04fc6c..94db90ccd234 100644 --- a/crates/accelerate/src/circuit_library/mod.rs +++ b/crates/accelerate/src/circuit_library/mod.rs @@ -13,8 +13,10 @@ use pyo3::prelude::*; mod entanglement; +mod pauli_feature_map; pub fn circuit_library(m: &Bound) -> PyResult<()> { + m.add_wrapped(wrap_pyfunction!(pauli_feature_map::pauli_feature_map))?; m.add_wrapped(wrap_pyfunction!(entanglement::get_entangler_map))?; Ok(()) } diff --git a/crates/accelerate/src/circuit_library/pauli_feature_map.rs b/crates/accelerate/src/circuit_library/pauli_feature_map.rs new file mode 100644 index 000000000000..53e84a197f1d --- /dev/null +++ b/crates/accelerate/src/circuit_library/pauli_feature_map.rs @@ -0,0 +1,346 @@ +// This code is part of Qiskit. +// +// (C) Copyright IBM 2024 +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE.txt file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +use itertools::Itertools; +use pyo3::prelude::*; +use pyo3::types::PySequence; +use pyo3::types::PyString; +use qiskit_circuit::circuit_data::CircuitData; +use qiskit_circuit::imports; +use qiskit_circuit::operations::PyInstruction; +use qiskit_circuit::operations::{add_param, multiply_param, multiply_params, Param, StandardGate}; +use qiskit_circuit::packed_instruction::PackedOperation; +use qiskit_circuit::{Clbit, Qubit}; +use smallvec::{smallvec, SmallVec}; +use std::f64::consts::PI; + +use crate::circuit_library::entanglement; +use crate::QiskitError; + +// custom math and types for a more readable code +const PI2: f64 = PI / 2.; +type Instruction = ( + PackedOperation, + SmallVec<[Param; 3]>, + Vec, + Vec, +); +type StandardInstruction = (StandardGate, SmallVec<[Param; 3]>, SmallVec<[Qubit; 2]>); + +/// Return instructions (using only StandardGate operations) to implement a Pauli evolution +/// of a given Pauli string over a given time (as Param). +/// +/// The Pauli evolution is implemented as a basis transformation to the Pauli-Z basis, +/// followed by a CX-chain and then a single Pauli-Z rotation on the last qubit. Then the CX-chain +/// is uncomputed and the inverse basis transformation applied. E.g. for the evolution under the +/// Pauli string XIYZ we have the circuit +/// ┌───┐┌───────┐┌───┐ +/// 0: ─────────────────┤ X ├┤ Rz(2) ├┤ X ├────────────────── +/// ┌──────────┐┌───┐└─┬─┘└───────┘└─┬─┘┌───┐┌───────────┐ +/// 1: ┤ Rx(pi/2) ├┤ X ├──■─────────────■──┤ X ├┤ Rx(-pi/2) ├ +/// └──────────┘└─┬─┘ └─┬─┘└───────────┘ +/// 2: ──────────────┼───────────────────────┼─────────────── +/// ┌───┐ │ │ ┌───┐ +/// 3: ─┤ H ├────────■───────────────────────■──┤ H ├──────── +/// └───┘ └───┘ +fn pauli_evolution( + pauli: &str, + indices: Vec, + time: Param, +) -> impl Iterator + '_ { + // Get pairs of (pauli, qubit) that are active, i.e. that are not the identity. Note that + // the rest of the code also works if there are only identities, in which case we will + // effectively return an empty iterator. + let qubits = indices.iter().map(|i| Qubit(*i)).collect_vec(); + let binding = pauli.to_lowercase(); // lowercase for convenience + let active_paulis = binding + .as_str() + .chars() + .rev() // reverse due to Qiskit's bit ordering convention + .zip(qubits) + .filter(|(p, _)| *p != 'i') + .collect_vec(); + + // get the basis change: x -> HGate, y -> RXGate(pi/2), z -> nothing + let basis_change = active_paulis + .clone() + .into_iter() + .filter(|(p, _)| *p != 'z') + .map(|(p, q)| match p { + 'x' => (StandardGate::HGate, smallvec![], smallvec![q]), + 'y' => ( + StandardGate::RXGate, + smallvec![Param::Float(PI2)], + smallvec![q], + ), + _ => unreachable!("Invalid Pauli string."), // "z" and "i" have been filtered out + }); + + // get the inverse basis change + let inverse_basis_change = basis_change.clone().map(|(gate, _, qubit)| match gate { + StandardGate::HGate => (gate, smallvec![], qubit), + StandardGate::RXGate => (gate, smallvec![Param::Float(-PI2)], qubit), + _ => unreachable!(), + }); + + // get the CX chain down to the target rotation qubit + let chain_down = active_paulis + .clone() + .into_iter() + .map(|(_, q)| q) + .tuple_windows() // iterates over (q[i], q[i+1]) windows + .map(|(ctrl, target)| (StandardGate::CXGate, smallvec![], smallvec![ctrl, target])); + + // get the CX chain up (cannot use chain_down.rev since tuple_windows is not double ended) + let chain_up = active_paulis + .clone() + .into_iter() + .rev() + .map(|(_, q)| q) + .tuple_windows() + .map(|(target, ctrl)| (StandardGate::CXGate, smallvec![], smallvec![ctrl, target])); + + // get the RZ gate on the last qubit + let last_qubit = active_paulis.last().unwrap().1; + let z_rotation = std::iter::once(( + StandardGate::PhaseGate, + smallvec![time], + smallvec![last_qubit], + )); + + // and finally chain everything together + basis_change + .chain(chain_down) + .chain(z_rotation) + .chain(chain_up) + .chain(inverse_basis_change) +} + +/// Build a Pauli feature map circuit. +/// +/// Args: +/// feature_dimension: The feature dimension (i.e. the number of qubits). +/// parameters: A parameter vector with ``feature_dimension`` elements. Taken as input +/// here to avoid a call to Python constructing the vector. +/// reps: The number of repetitions of Hadamard + evolution layers. +/// entanglement: The entanglement, given as Python string or None (defaults to "full"). +/// paulis: The Pauli strings as list of strings or None (default to ["z", "zz"]). +/// alpha: A float multiplier for rotation angles. +/// insert_barriers: Whether to insert barriers in between the Hadamard and evolution layers. +/// data_map_func: An accumulation function that takes as input a vector of parameters the +/// current gate acts on and returns a scalar. +/// +/// Returns: +/// The ``CircuitData`` to construct the Pauli feature map. +#[pyfunction] +#[pyo3(signature = (feature_dimension, parameters, *, reps=1, entanglement=None, paulis=None, alpha=2.0, insert_barriers=false, data_map_func=None))] +#[allow(clippy::too_many_arguments)] +pub fn pauli_feature_map( + py: Python, + feature_dimension: u32, + parameters: Bound, + reps: usize, + entanglement: Option<&Bound>, + paulis: Option<&Bound>, + alpha: f64, + insert_barriers: bool, + data_map_func: Option<&Bound>, +) -> PyResult { + // normalize the Pauli strings + let pauli_strings = _get_paulis(feature_dimension, paulis)?; + + // set the default value for entanglement + let default = PyString::new_bound(py, "full"); + let entanglement = entanglement.unwrap_or(&default); + + // extract the parameters from the input variable ``parameters`` + let parameter_vector = parameters + .iter()? + .map(|el| Param::extract_no_coerce(&el?)) + .collect::>>()?; + + // construct a Barrier object Python side to (possibly) add to the circuit + let packed_barrier = if insert_barriers { + Some(_get_barrier(py, feature_dimension)?) + } else { + None + }; + + // Main work: construct the circuit instructions as iterator. Each repetition is constituted + // by a layer of Hadamards and the Pauli evolutions of the specified Paulis. + // Note that we eagerly trigger errors, since the final CircuitData::from_packed_operations + // does not allow Result objects in the iterator. + let mut packed_insts: Vec = Vec::new(); + for rep in 0..reps { + // add H layer + packed_insts.extend(_get_h_layer(feature_dimension)); + + if insert_barriers { + packed_insts.push(packed_barrier.clone().unwrap()); + } + + // add evolutions + let evo_layer = _get_evolution_layer( + py, + feature_dimension, + rep, + alpha, + ¶meter_vector, + &pauli_strings, + entanglement, + data_map_func, + )?; + packed_insts.extend(evo_layer); + + // add barriers, if necessary + if insert_barriers && rep < reps - 1 { + packed_insts.push(packed_barrier.clone().unwrap()); + } + } + + CircuitData::from_packed_operations(py, feature_dimension, 0, packed_insts, Param::Float(0.0)) +} + +fn _get_h_layer(feature_dimension: u32) -> impl Iterator { + (0..feature_dimension).map(|i| { + ( + StandardGate::HGate.into(), + smallvec![], + vec![Qubit(i)], + vec![] as Vec, + ) + }) +} + +#[allow(clippy::too_many_arguments)] +fn _get_evolution_layer<'a>( + py: Python<'a>, + feature_dimension: u32, + rep: usize, + alpha: f64, + parameter_vector: &'a [Param], + pauli_strings: &'a [String], + entanglement: &'a Bound, + data_map_func: Option<&'a Bound>, +) -> PyResult> { + let mut insts: Vec = Vec::new(); + + for pauli in pauli_strings { + let block_size = pauli.len() as u32; + let entanglement = + entanglement::get_entanglement(feature_dimension, block_size, entanglement, rep)?; + + for indices in entanglement { + let indices = indices?; + let active_parameters: Vec = indices + .clone() + .iter() + .map(|i| parameter_vector[*i as usize].clone()) + .collect(); + + let angle = match data_map_func { + Some(fun) => fun.call1((active_parameters,))?.extract()?, + None => _default_reduce(py, active_parameters), + }; + + // Get the pauli evolution and map it into + // (PackedOperation, SmallVec<[Params; 3]>, Vec, Vec) + // to call CircuitData::from_packed_operations. This is needed since we might + // have to interject barriers, which are not a standard gate and prevents us + // from using CircuitData::from_standard_gates. + let evo = pauli_evolution(pauli, indices.clone(), multiply_param(&angle, alpha, py)) + .map(|(gate, params, qargs)| { + (gate.into(), params, qargs.to_vec(), vec![] as Vec) + }) + .collect::>(); + insts.extend(evo); + } + } + + Ok(insts) +} + +/// The default data_map_func for Pauli feature maps. For a parameter vector (x1, ..., xN), this +/// implements +/// (pi - x1) (pi - x2) ... (pi - xN) +/// unless there is only one parameter, in which case it returns just the value. +fn _default_reduce(py: Python, parameters: Vec) -> Param { + if parameters.len() == 1 { + parameters[0].clone() + } else { + let acc = parameters.iter().fold(Param::Float(1.0), |acc, param| { + multiply_params(acc, add_param(param, -PI, py), py) + }); + if parameters.len() % 2 == 0 { + acc + } else { + multiply_param(&acc, -1.0, py) // take care of parity + } + } +} + +/// Normalize the Pauli strings to a Vec. We first define the default, which is +/// ["z", "zz"], unless we only have a single qubit, in which case we default to ["z"]. +/// Then, ``pauli_strings`` is either set to the default, or we try downcasting to a +/// PyString->String, followed by a check whether the feature dimension is large enough +/// for the Pauli (e.g. we cannot implement a "zzz" Pauli on a 2 qubit circuit). +fn _get_paulis( + feature_dimension: u32, + paulis: Option<&Bound>, +) -> PyResult> { + let default_pauli: Vec = if feature_dimension == 1 { + vec!["z".to_string()] + } else { + vec!["z".to_string(), "zz".to_string()] + }; + + paulis.map_or_else( + || Ok(default_pauli), // use Ok() since we might raise an error in the other arm + |v| { + let v = PySequenceMethods::to_list(v)?; // sequence to list + v.iter() // iterate over the list of Paulis + .map(|el| { + // Get the string and check whether it fits the feature dimension + let as_string = (*el.downcast::()?).to_string(); + if as_string.len() > feature_dimension as usize { + Err(QiskitError::new_err(format!( + "feature_dimension ({}) smaller than the Pauli ({})", + feature_dimension, as_string + ))) + } else { + Ok(as_string) + } + }) + .collect::>>() + }, + ) +} + +/// Get a barrier object from Python space. +fn _get_barrier(py: Python, feature_dimension: u32) -> PyResult { + let barrier_cls = imports::BARRIER.get_bound(py); + let barrier = barrier_cls.call1((feature_dimension,))?; + let barrier_inst = PyInstruction { + qubits: feature_dimension, + clbits: 0, + params: 0, + op_name: "barrier".to_string(), + control_flow: false, + instruction: barrier.into(), + }; + Ok(( + barrier_inst.into(), + smallvec![], + (0..feature_dimension).map(Qubit).collect(), + vec![] as Vec, + )) +} diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index a8f6d9562559..5c77f8ef7d17 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -109,6 +109,7 @@ pub static SWITCH_CASE_OP_CHECK: ImportOnceCell = pub static FOR_LOOP_OP_CHECK: ImportOnceCell = ImportOnceCell::new("qiskit.dagcircuit.dagnode", "_for_loop_eq"); pub static UUID: ImportOnceCell = ImportOnceCell::new("uuid", "UUID"); +pub static BARRIER: ImportOnceCell = ImportOnceCell::new("qiskit.circuit", "Barrier"); pub static UNITARY_GATE: ImportOnceCell = ImportOnceCell::new( "qiskit.circuit.library.generalized_gates.unitary", "UnitaryGate", diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index a3fd2fc83c3d..2a341d687f6c 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -2051,7 +2051,8 @@ fn clone_param(param: &Param, py: Python) -> Param { } } -fn multiply_param(param: &Param, mult: f64, py: Python) -> Param { +/// Multiply a ``Param`` with a float. +pub fn multiply_param(param: &Param, mult: f64, py: Python) -> Param { match param { Param::Float(theta) => Param::Float(theta * mult), Param::ParameterExpression(theta) => Param::ParameterExpression( @@ -2064,7 +2065,24 @@ fn multiply_param(param: &Param, mult: f64, py: Python) -> Param { } } -fn add_param(param: &Param, summand: f64, py: Python) -> Param { +/// Multiply two ``Param``s. +pub fn multiply_params(param1: Param, param2: Param, py: Python) -> Param { + match (¶m1, ¶m2) { + (Param::Float(theta), Param::Float(lambda)) => Param::Float(theta * lambda), + (param, Param::Float(theta)) => multiply_param(param, *theta, py), + (Param::Float(theta), param) => multiply_param(param, *theta, py), + (Param::ParameterExpression(p1), Param::ParameterExpression(p2)) => { + Param::ParameterExpression( + p1.clone_ref(py) + .call_method1(py, intern!(py, "__rmul__"), (p2,)) + .expect("Parameter expression multiplication failed"), + ) + } + _ => unreachable!("Unsupported multiplication."), + } +} + +pub fn add_param(param: &Param, summand: f64, py: Python) -> Param { match param { Param::Float(theta) => Param::Float(*theta + summand), Param::ParameterExpression(theta) => Param::ParameterExpression( diff --git a/qiskit/circuit/library/__init__.py b/qiskit/circuit/library/__init__.py index 39266cf4ca17..9dd1fdebf08a 100644 --- a/qiskit/circuit/library/__init__.py +++ b/qiskit/circuit/library/__init__.py @@ -555,6 +555,9 @@ QAOAAnsatz, ) from .data_preparation import ( + z_feature_map, + zz_feature_map, + pauli_feature_map, PauliFeatureMap, ZFeatureMap, ZZFeatureMap, diff --git a/qiskit/circuit/library/data_preparation/__init__.py b/qiskit/circuit/library/data_preparation/__init__.py index 192308a3a7f5..475046d78338 100644 --- a/qiskit/circuit/library/data_preparation/__init__.py +++ b/qiskit/circuit/library/data_preparation/__init__.py @@ -38,15 +38,18 @@ """ -from .pauli_feature_map import PauliFeatureMap -from .z_feature_map import ZFeatureMap -from .zz_feature_map import ZZFeatureMap +from .pauli_feature_map import PauliFeatureMap, pauli_feature_map, z_feature_map, zz_feature_map +from ._z_feature_map import ZFeatureMap +from ._zz_feature_map import ZZFeatureMap from .state_preparation import StatePreparation, UniformSuperpositionGate from .initializer import Initialize __all__ = [ + "pauli_feature_map", "PauliFeatureMap", + "z_feature_map", "ZFeatureMap", + "zz_feature_map", "ZZFeatureMap", "StatePreparation", "UniformSuperpositionGate", diff --git a/qiskit/circuit/library/data_preparation/z_feature_map.py b/qiskit/circuit/library/data_preparation/_z_feature_map.py similarity index 52% rename from qiskit/circuit/library/data_preparation/z_feature_map.py rename to qiskit/circuit/library/data_preparation/_z_feature_map.py index 902de1a6a5ac..451776067114 100644 --- a/qiskit/circuit/library/data_preparation/z_feature_map.py +++ b/qiskit/circuit/library/data_preparation/_z_feature_map.py @@ -14,6 +14,7 @@ from typing import Callable, Optional import numpy as np +from qiskit.utils.deprecation import deprecate_func from .pauli_feature_map import PauliFeatureMap @@ -25,13 +26,13 @@ class ZFeatureMap(PauliFeatureMap): .. parsed-literal:: - ┌───┐┌──────────────┐┌───┐┌──────────────┐ - ┤ H ├┤ U1(2.0*x[0]) ├┤ H ├┤ U1(2.0*x[0]) ├ - ├───┤├──────────────┤├───┤├──────────────┤ - ┤ H ├┤ U1(2.0*x[1]) ├┤ H ├┤ U1(2.0*x[1]) ├ - ├───┤├──────────────┤├───┤├──────────────┤ - ┤ H ├┤ U1(2.0*x[2]) ├┤ H ├┤ U1(2.0*x[2]) ├ - └───┘└──────────────┘└───┘└──────────────┘ + ┌───┐┌─────────────┐┌───┐┌─────────────┐ + ┤ H ├┤ P(2.0*x[0]) ├┤ H ├┤ P(2.0*x[0]) ├ + ├───┤├─────────────┤├───┤├─────────────┤ + ┤ H ├┤ U(2.0*x[1]) ├┤ H ├┤ P(2.0*x[1]) ├ + ├───┤├─────────────┤├───┤├─────────────┤ + ┤ H ├┤ P(2.0*x[2]) ├┤ H ├┤ P(2.0*x[2]) ├ + └───┘└─────────────┘└───┘└─────────────┘ This is a sub-class of :class:`~qiskit.circuit.library.PauliFeatureMap` where the Pauli strings are fixed as `['Z']`. As a result the first order expansion will be a circuit without @@ -40,38 +41,48 @@ class ZFeatureMap(PauliFeatureMap): Examples: >>> prep = ZFeatureMap(3, reps=3, insert_barriers=True) - >>> print(prep) - ┌───┐ ░ ┌──────────────┐ ░ ┌───┐ ░ ┌──────────────┐ ░ ┌───┐ ░ ┌──────────────┐ - q_0: ┤ H ├─░─┤ U1(2.0*x[0]) ├─░─┤ H ├─░─┤ U1(2.0*x[0]) ├─░─┤ H ├─░─┤ U1(2.0*x[0]) ├ - ├───┤ ░ ├──────────────┤ ░ ├───┤ ░ ├──────────────┤ ░ ├───┤ ░ ├──────────────┤ - q_1: ┤ H ├─░─┤ U1(2.0*x[1]) ├─░─┤ H ├─░─┤ U1(2.0*x[1]) ├─░─┤ H ├─░─┤ U1(2.0*x[1]) ├ - ├───┤ ░ ├──────────────┤ ░ ├───┤ ░ ├──────────────┤ ░ ├───┤ ░ ├──────────────┤ - q_2: ┤ H ├─░─┤ U1(2.0*x[2]) ├─░─┤ H ├─░─┤ U1(2.0*x[2]) ├─░─┤ H ├─░─┤ U1(2.0*x[2]) ├ - └───┘ ░ └──────────────┘ ░ └───┘ ░ └──────────────┘ ░ └───┘ ░ └──────────────┘ + >>> print(prep.decompose()) + ┌───┐ ░ ┌─────────────┐ ░ ┌───┐ ░ ┌─────────────┐ ░ ┌───┐ ░ ┌─────────────┐ + q_0: ┤ H ├─░─┤ P(2.0*x[0]) ├─░─┤ H ├─░─┤ P(2.0*x[0]) ├─░─┤ H ├─░─┤ P(2.0*x[0]) ├ + ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ + q_1: ┤ H ├─░─┤ P(2.0*x[1]) ├─░─┤ H ├─░─┤ P(2.0*x[1]) ├─░─┤ H ├─░─┤ P(2.0*x[1]) ├ + ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ + q_2: ┤ H ├─░─┤ P(2.0*x[2]) ├─░─┤ H ├─░─┤ P(2.0*x[2]) ├─░─┤ H ├─░─┤ P(2.0*x[2]) ├ + └───┘ ░ └─────────────┘ ░ └───┘ ░ └─────────────┘ ░ └───┘ ░ └─────────────┘ >>> data_map = lambda x: x[0]*x[0] + 1 # note: input is an array >>> prep = ZFeatureMap(3, reps=1, data_map_func=data_map) - >>> print(prep) - ┌───┐┌───────────────────────┐ - q_0: ┤ H ├┤ U1(2.0*x[0]**2 + 2.0) ├ - ├───┤├───────────────────────┤ - q_1: ┤ H ├┤ U1(2.0*x[1]**2 + 2.0) ├ - ├───┤├───────────────────────┤ - q_2: ┤ H ├┤ U1(2.0*x[2]**2 + 2.0) ├ - └───┘└───────────────────────┘ - - >>> classifier = ZFeatureMap(3, reps=1) + RY(3, reps=1) - >>> print(classifier) - ┌───┐┌──────────────┐┌──────────┐ ┌──────────┐ - q_0: ┤ H ├┤ U1(2.0*x[0]) ├┤ RY(θ[0]) ├─■──■─┤ RY(θ[3]) ├──────────── - ├───┤├──────────────┤├──────────┤ │ │ └──────────┘┌──────────┐ - q_1: ┤ H ├┤ U1(2.0*x[1]) ├┤ RY(θ[1]) ├─■──┼──────■──────┤ RY(θ[4]) ├ - ├───┤├──────────────┤├──────────┤ │ │ ├──────────┤ - q_2: ┤ H ├┤ U1(2.0*x[2]) ├┤ RY(θ[2]) ├────■──────■──────┤ RY(θ[5]) ├ - └───┘└──────────────┘└──────────┘ └──────────┘ + >>> print(prep.decompose()) + ┌───┐┌──────────────────────┐ + q_0: ┤ H ├┤ P(2.0*x[0]**2 + 2.0) ├ + ├───┤├──────────────────────┤ + q_1: ┤ H ├┤ P(2.0*x[1]**2 + 2.0) ├ + ├───┤├──────────────────────┤ + q_2: ┤ H ├┤ P(2.0*x[2]**2 + 2.0) ├ + └───┘└──────────────────────┘ + + >>> from qiskit.circuit.library import TwoLocal + >>> ry = TwoLocal(3, "ry", "cz", reps=1) + >>> classifier = ZFeatureMap(3, reps=1) + ry + >>> print(classifier.decompose()) + ┌───┐┌─────────────┐┌──────────┐ ┌──────────┐ + q_0: ┤ H ├┤ P(2.0*x[0]) ├┤ RY(θ[0]) ├─■──■─┤ RY(θ[3]) ├──────────── + ├───┤├─────────────┤├──────────┤ │ │ └──────────┘┌──────────┐ + q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ RY(θ[1]) ├─■──┼──────■──────┤ RY(θ[4]) ├ + ├───┤├─────────────┤├──────────┤ │ │ ├──────────┤ + q_2: ┤ H ├┤ P(2.0*x[2]) ├┤ RY(θ[2]) ├────■──────■──────┤ RY(θ[5]) ├ + └───┘└─────────────┘└──────────┘ └──────────┘ """ + @deprecate_func( + since="1.3", + additional_msg=( + "Use the z_feature_map function as a replacement. Note that this will no longer " + "return a BlueprintCircuit, but just a plain QuantumCircuit." + ), + pending=True, + ) def __init__( self, feature_dimension: int, diff --git a/qiskit/circuit/library/data_preparation/zz_feature_map.py b/qiskit/circuit/library/data_preparation/_zz_feature_map.py similarity index 71% rename from qiskit/circuit/library/data_preparation/zz_feature_map.py rename to qiskit/circuit/library/data_preparation/_zz_feature_map.py index 2f51b8f63482..2a170513dfdb 100644 --- a/qiskit/circuit/library/data_preparation/zz_feature_map.py +++ b/qiskit/circuit/library/data_preparation/_zz_feature_map.py @@ -14,6 +14,7 @@ from typing import Callable, List, Union, Optional, Dict, Tuple import numpy as np +from qiskit.utils.deprecation import deprecate_func from .pauli_feature_map import PauliFeatureMap @@ -24,13 +25,13 @@ class ZZFeatureMap(PauliFeatureMap): .. parsed-literal:: - ┌───┐┌─────────────────┐ - ┤ H ├┤ U1(2.0*φ(x[0])) ├──■────────────────────────────■──────────────────────────────────── - ├───┤├─────────────────┤┌─┴─┐┌──────────────────────┐┌─┴─┐ - ┤ H ├┤ U1(2.0*φ(x[1])) ├┤ X ├┤ U1(2.0*φ(x[0],x[1])) ├┤ X ├──■────────────────────────────■── - ├───┤├─────────────────┤└───┘└──────────────────────┘└───┘┌─┴─┐┌──────────────────────┐┌─┴─┐ - ┤ H ├┤ U1(2.0*φ(x[2])) ├──────────────────────────────────┤ X ├┤ U1(2.0*φ(x[1],x[2])) ├┤ X ├ - └───┘└─────────────────┘ └───┘└──────────────────────┘└───┘ + ┌───┐┌────────────────┐ + ┤ H ├┤ P(2.0*φ(x[0])) ├──■───────────────────────────■─────────────────────────────────── + ├───┤├────────────────┤┌─┴─┐┌─────────────────────┐┌─┴─┐ + ┤ H ├┤ P(2.0*φ(x[1])) ├┤ X ├┤ P(2.0*φ(x[0],x[1])) ├┤ X ├──■───────────────────────────■── + ├───┤├────────────────┤└───┘└─────────────────────┘└───┘┌─┴─┐┌─────────────────────┐┌─┴─┐ + ┤ H ├┤ P(2.0*φ(x[2])) ├─────────────────────────────────┤ X ├┤ P(2.0*φ(x[1],x[2])) ├┤ X ├ + └───┘└────────────────┘ └───┘└─────────────────────┘└───┘ where :math:`\varphi` is a classical non-linear function, which defaults to :math:`\varphi(x) = x` if and :math:`\varphi(x,y) = (\pi - x)(\pi - y)`. @@ -39,12 +40,12 @@ class ZZFeatureMap(PauliFeatureMap): >>> from qiskit.circuit.library import ZZFeatureMap >>> prep = ZZFeatureMap(2, reps=1) - >>> print(prep) - ┌───┐┌──────────────┐ - q_0: ┤ H ├┤ U1(2.0*x[0]) ├──■───────────────────────────────────────■── - ├───┤├──────────────┤┌─┴─┐┌─────────────────────────────────┐┌─┴─┐ - q_1: ┤ H ├┤ U1(2.0*x[1]) ├┤ X ├┤ U1(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├ - └───┘└──────────────┘└───┘└─────────────────────────────────┘└───┘ + >>> print(prep.decompose()) + ┌───┐┌─────────────┐ + q_0: ┤ H ├┤ P(2.0*x[0]) ├──■──────────────────────────────────────■── + ├───┤├─────────────┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐ + q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├ + └───┘└─────────────┘└───┘└────────────────────────────────┘└───┘ >>> from qiskit.circuit.library import EfficientSU2 >>> classifier = ZZFeatureMap(3) + EfficientSU2(3) @@ -71,6 +72,14 @@ class ZZFeatureMap(PauliFeatureMap): OrderedDict([('ZZFeatureMap', 1), ('EfficientSU2', 1)]) """ + @deprecate_func( + since="1.3", + additional_msg=( + "Use the z_feature_map function as a replacement. Note that this will no longer " + "return a BlueprintCircuit, but just a plain QuantumCircuit." + ), + pending=True, + ) def __init__( self, feature_dimension: int, diff --git a/qiskit/circuit/library/data_preparation/pauli_feature_map.py b/qiskit/circuit/library/data_preparation/pauli_feature_map.py index 8cad7d23835b..a40deb6ea18b 100644 --- a/qiskit/circuit/library/data_preparation/pauli_feature_map.py +++ b/qiskit/circuit/library/data_preparation/pauli_feature_map.py @@ -11,17 +11,316 @@ # that they have been altered from the originals. """The Pauli expansion circuit module.""" -from typing import Optional, Callable, List, Union, Sequence, Dict, Tuple + +from __future__ import annotations + +from collections.abc import Sequence, Mapping +from typing import Optional, Callable, List, Union, Dict, Tuple from functools import reduce import numpy as np from qiskit.circuit import QuantumCircuit -from qiskit.circuit import Parameter, ParameterVector +from qiskit.circuit import Parameter, ParameterVector, ParameterExpression from qiskit.circuit.library.standard_gates import HGate +from qiskit.utils.deprecation import deprecate_func +from qiskit._accelerate.circuit_library import pauli_feature_map as _fast_map from ..n_local.n_local import NLocal +def _normalize_entanglement( + entanglement: str | Mapping[int, Sequence[Sequence[int]]] +) -> str | dict[int, list[tuple[int]]]: + if isinstance(entanglement, str): + return entanglement + + return { + num_paulis: [tuple(connections) for connections in ent] + for num_paulis, ent in entanglement.items() + } + + +def pauli_feature_map( + feature_dimension: int, + reps: int = 2, + entanglement: ( + str + | Mapping[int, Sequence[Sequence[int]]] + | Callable[[int], str | Mapping[int, Sequence[Sequence[int]]]] + ) = "full", + alpha: float = 2.0, + paulis: list[str] | None = None, + data_map_func: Callable[[Parameter], ParameterExpression] | None = None, + parameter_prefix: str = "x", + insert_barriers: bool = False, + name: str = "PauliFeatureMap", +) -> QuantumCircuit: + r"""The Pauli expansion circuit. + + The Pauli expansion circuit is a data encoding circuit that transforms input data + :math:`\vec{x} \in \mathbb{R}^n`, where :math:`n` is the ``feature_dimension``, as + + .. math:: + + U_{\Phi(\vec{x})}=\exp\left(i\sum_{S \in \mathcal{I}} + \phi_S(\vec{x})\prod_{i\in S} P_i\right). + + Here, :math:`S` is a set of qubit indices that describes the connections in the feature map, + :math:`\mathcal{I}` is a set containing all these index sets, and + :math:`P_i \in \{I, X, Y, Z\}`. Per default the data-mapping + :math:`\phi_S` is + + .. math:: + + \phi_S(\vec{x}) = \begin{cases} + x_i \text{ if } S = \{i\} \\ + \prod_{j \in S} (\pi - x_j) \text{ if } |S| > 1 + \end{cases}. + + The possible connections can be set using the ``entanglement`` and ``paulis`` arguments. + For example, for single-qubit :math:`Z` rotations and two-qubit :math:`YY` interactions + between all qubit pairs, we can set:: + + + circuit = pauli_feature_map(..., paulis=["Z", "YY"], entanglement="full") + + which will produce blocks of the form + + .. parsed-literal:: + + ┌───┐┌─────────────┐┌──────────┐ ┌───────────┐ + ┤ H ├┤ P(2.0*x[0]) ├┤ RX(pi/2) ├──■──────────────────────────────────────■──┤ RX(-pi/2) ├ + ├───┤├─────────────┤├──────────┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐├───────────┤ + ┤ H ├┤ P(2.0*x[1]) ├┤ RX(pi/2) ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├┤ RX(-pi/2) ├ + └───┘└─────────────┘└──────────┘└───┘└────────────────────────────────┘└───┘└───────────┘ + + The circuit contains ``reps`` repetitions of this transformation. + + Please refer to :func:`.z_feature_map` for the case of single-qubit Pauli-:math:`Z` rotations + and to :func:`.zz_feature_map` for the single- and two-qubit Pauli-:math:`Z` rotations. + + Examples: + + >>> prep = pauli_feature_map(2, reps=1, paulis=["ZZ"]) + >>> print(prep) + ┌───┐ + q_0: ┤ H ├──■──────────────────────────────────────■── + ├───┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐ + q_1: ┤ H ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├ + └───┘└───┘└────────────────────────────────┘└───┘ + + >>> prep = pauli_feature_map(2, reps=1, paulis=["Z", "XX"]) + >>> print(prep) + ┌───┐┌─────────────┐┌───┐ ┌───┐ + q_0: ┤ H ├┤ P(2.0*x[0]) ├┤ H ├──■──────────────────────────────────────■──┤ H ├ + ├───┤├─────────────┤├───┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐├───┤ + q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ H ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├┤ H ├ + └───┘└─────────────┘└───┘└───┘└────────────────────────────────┘└───┘└───┘ + + >>> prep = pauli_feature_map(2, reps=1, paulis=["ZY"]) + >>> print(prep) + ┌───┐┌──────────┐ ┌───────────┐ + q_0: ┤ H ├┤ RX(pi/2) ├──■──────────────────────────────────────■──┤ RX(-pi/2) ├ + ├───┤└──────────┘┌─┴─┐┌────────────────────────────────┐┌─┴─┐└───────────┘ + q_1: ┤ H ├────────────┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├───────────── + └───┘ └───┘└────────────────────────────────┘└───┘ + + >>> from qiskit.circuit.library import EfficientSU2 + >>> prep = pauli_feature_map(3, reps=3, paulis=["Z", "YY", "ZXZ"]) + >>> wavefunction = EfficientSU2(3) + >>> classifier = prep.compose(wavefunction) + >>> classifier.num_parameters + 27 + >>> classifier.count_ops() + OrderedDict([('cx', 39), ('rx', 36), ('u1', 21), ('h', 15), ('ry', 12), ('rz', 12)]) + + References: + + [1] Havlicek et al. Supervised learning with quantum enhanced feature spaces, + `Nature 567, 209-212 (2019) `__. + """ + # create parameter vector used in the Pauli feature map + parameters = ParameterVector(parameter_prefix, feature_dimension) + + # the Rust implementation expects the entanglement to be a str or list[tuple[int]] (or the + # callable to return these types), therefore we normalize the entanglement here + if callable(entanglement): + normalized = lambda offset: _normalize_entanglement(entanglement(offset)) + else: + normalized = _normalize_entanglement(entanglement) + + # construct from Rust + circuit = QuantumCircuit._from_circuit_data( + _fast_map( + feature_dimension, + paulis=paulis, + entanglement=normalized, + reps=reps, + parameters=parameters, + data_map_func=data_map_func, + alpha=alpha, + insert_barriers=insert_barriers, + ) + ) + circuit.name = name + + return circuit + + +def z_feature_map( + feature_dimension: int, + reps: int = 2, + entanglement: ( + str | Sequence[Sequence[int]] | Callable[[int], str | Sequence[Sequence[int]]] + ) = "full", + alpha: float = 2.0, + data_map_func: Callable[[Parameter], ParameterExpression] | None = None, + parameter_prefix: str = "x", + insert_barriers: bool = False, + name: str = "ZFeatureMap", +) -> QuantumCircuit: + """The first order Pauli Z-evolution circuit. + + On 3 qubits and with 2 repetitions the circuit is represented by: + + .. parsed-literal:: + + ┌───┐┌─────────────┐┌───┐┌─────────────┐ + ┤ H ├┤ P(2.0*x[0]) ├┤ H ├┤ P(2.0*x[0]) ├ + ├───┤├─────────────┤├───┤├─────────────┤ + ┤ H ├┤ U(2.0*x[1]) ├┤ H ├┤ P(2.0*x[1]) ├ + ├───┤├─────────────┤├───┤├─────────────┤ + ┤ H ├┤ P(2.0*x[2]) ├┤ H ├┤ P(2.0*x[2]) ├ + └───┘└─────────────┘└───┘└─────────────┘ + + This is a sub-class of :class:`~qiskit.circuit.library.PauliFeatureMap` where the Pauli + strings are fixed as `['Z']`. As a result the first order expansion will be a circuit without + entangling gates. + + Examples: + + >>> prep = z_feature_map(3, reps=3, insert_barriers=True) + >>> print(prep) + ┌───┐ ░ ┌─────────────┐ ░ ┌───┐ ░ ┌─────────────┐ ░ ┌───┐ ░ ┌─────────────┐ + q_0: ┤ H ├─░─┤ P(2.0*x[0]) ├─░─┤ H ├─░─┤ P(2.0*x[0]) ├─░─┤ H ├─░─┤ P(2.0*x[0]) ├ + ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ + q_1: ┤ H ├─░─┤ P(2.0*x[1]) ├─░─┤ H ├─░─┤ P(2.0*x[1]) ├─░─┤ H ├─░─┤ P(2.0*x[1]) ├ + ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ ░ ├───┤ ░ ├─────────────┤ + q_2: ┤ H ├─░─┤ P(2.0*x[2]) ├─░─┤ H ├─░─┤ P(2.0*x[2]) ├─░─┤ H ├─░─┤ P(2.0*x[2]) ├ + └───┘ ░ └─────────────┘ ░ └───┘ ░ └─────────────┘ ░ └───┘ ░ └─────────────┘ + + >>> data_map = lambda x: x[0]*x[0] + 1 # note: input is an array + >>> prep = z_feature_map(3, reps=1, data_map_func=data_map) + >>> print(prep) + ┌───┐┌──────────────────────┐ + q_0: ┤ H ├┤ P(2.0*x[0]**2 + 2.0) ├ + ├───┤├──────────────────────┤ + q_1: ┤ H ├┤ P(2.0*x[1]**2 + 2.0) ├ + ├───┤├──────────────────────┤ + q_2: ┤ H ├┤ P(2.0*x[2]**2 + 2.0) ├ + └───┘└──────────────────────┘ + + >>> from qiskit.circuit.library import TwoLocal + >>> ry = TwoLocal(3, "ry", "cz", reps=1).decompose() + >>> classifier = z_feature_map(3, reps=1) + ry + >>> print(classifier) + ┌───┐┌─────────────┐┌──────────┐ ┌──────────┐ + q_0: ┤ H ├┤ P(2.0*x[0]) ├┤ RY(θ[0]) ├─■──■─┤ RY(θ[3]) ├──────────── + ├───┤├─────────────┤├──────────┤ │ │ └──────────┘┌──────────┐ + q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ RY(θ[1]) ├─■──┼──────■──────┤ RY(θ[4]) ├ + ├───┤├─────────────┤├──────────┤ │ │ ├──────────┤ + q_2: ┤ H ├┤ P(2.0*x[2]) ├┤ RY(θ[2]) ├────■──────■──────┤ RY(θ[5]) ├ + └───┘└─────────────┘└──────────┘ └──────────┘ + + """ + return pauli_feature_map( + feature_dimension=feature_dimension, + reps=reps, + entanglement=entanglement, + alpha=alpha, + paulis=["z"], + data_map_func=data_map_func, + parameter_prefix=parameter_prefix, + insert_barriers=insert_barriers, + name=name, + ) + + +def zz_feature_map( + feature_dimension: int, + reps: int = 2, + entanglement: ( + str | Sequence[Sequence[int]] | Callable[[int], str | Sequence[Sequence[int]]] + ) = "full", + alpha: float = 2.0, + data_map_func: Callable[[Parameter], ParameterExpression] | None = None, + parameter_prefix: str = "x", + insert_barriers: bool = False, + name: str = "ZZFeatureMap", +) -> QuantumCircuit: + r"""Second-order Pauli-Z evolution circuit. + + For 3 qubits and 1 repetition and linear entanglement the circuit is represented by: + + .. parsed-literal:: + + ┌───┐┌────────────────┐ + ┤ H ├┤ P(2.0*φ(x[0])) ├──■───────────────────────────■─────────────────────────────────── + ├───┤├────────────────┤┌─┴─┐┌─────────────────────┐┌─┴─┐ + ┤ H ├┤ P(2.0*φ(x[1])) ├┤ X ├┤ P(2.0*φ(x[0],x[1])) ├┤ X ├──■───────────────────────────■── + ├───┤├────────────────┤└───┘└─────────────────────┘└───┘┌─┴─┐┌─────────────────────┐┌─┴─┐ + ┤ H ├┤ P(2.0*φ(x[2])) ├─────────────────────────────────┤ X ├┤ P(2.0*φ(x[1],x[2])) ├┤ X ├ + └───┘└────────────────┘ └───┘└─────────────────────┘└───┘ + + where :math:`\varphi` is a classical non-linear function, which defaults to :math:`\varphi(x) = x` + if and :math:`\varphi(x,y) = (\pi - x)(\pi - y)`. + + Examples: + + >>> from qiskit.circuit.library import ZZFeatureMap + >>> prep = zz_feature_map(2, reps=1) + >>> print(prep) + ┌───┐┌─────────────┐ + q_0: ┤ H ├┤ P(2.0*x[0]) ├──■──────────────────────────────────────■── + ├───┤├─────────────┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐ + q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├ + └───┘└─────────────┘└───┘└────────────────────────────────┘└───┘ + + >>> from qiskit.circuit.library import EfficientSU2 + >>> classifier = zz_feature_map(3) + EfficientSU2(3) + >>> classifier.num_parameters + 15 + >>> classifier.parameters # 'x' for the data preparation, 'θ' for the SU2 parameters + ParameterView([ + ParameterVectorElement(x[0]), ParameterVectorElement(x[1]), + ParameterVectorElement(x[2]), ParameterVectorElement(θ[0]), + ParameterVectorElement(θ[1]), ParameterVectorElement(θ[2]), + ParameterVectorElement(θ[3]), ParameterVectorElement(θ[4]), + ParameterVectorElement(θ[5]), ParameterVectorElement(θ[6]), + ParameterVectorElement(θ[7]), ParameterVectorElement(θ[8]), + ParameterVectorElement(θ[9]), ParameterVectorElement(θ[10]), + ParameterVectorElement(θ[11]), ParameterVectorElement(θ[12]), + ParameterVectorElement(θ[13]), ParameterVectorElement(θ[14]), + ParameterVectorElement(θ[15]), ParameterVectorElement(θ[16]), + ParameterVectorElement(θ[17]), ParameterVectorElement(θ[18]), + ParameterVectorElement(θ[19]), ParameterVectorElement(θ[20]), + ParameterVectorElement(θ[21]), ParameterVectorElement(θ[22]), + ParameterVectorElement(θ[23]) + ]) + """ + return pauli_feature_map( + feature_dimension=feature_dimension, + reps=reps, + entanglement=entanglement, + alpha=alpha, + paulis=["z", "zz"], + data_map_func=data_map_func, + parameter_prefix=parameter_prefix, + insert_barriers=insert_barriers, + name=name, + ) + + class PauliFeatureMap(NLocal): r"""The Pauli Expansion circuit. @@ -56,11 +355,11 @@ class PauliFeatureMap(NLocal): .. parsed-literal:: - ┌───┐┌──────────────┐┌──────────┐ ┌───────────┐ - ┤ H ├┤ U1(2.0*x[0]) ├┤ RX(pi/2) ├──■───────────────────────────────────────■──┤ RX(-pi/2) ├ - ├───┤├──────────────┤├──────────┤┌─┴─┐┌─────────────────────────────────┐┌─┴─┐├───────────┤ - ┤ H ├┤ U1(2.0*x[1]) ├┤ RX(pi/2) ├┤ X ├┤ U1(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├┤ RX(-pi/2) ├ - └───┘└──────────────┘└──────────┘└───┘└─────────────────────────────────┘└───┘└───────────┘ + ┌───┐┌─────────────┐┌──────────┐ ┌───────────┐ + ┤ H ├┤ P(2.0*x[0]) ├┤ RX(pi/2) ├──■──────────────────────────────────────■──┤ RX(-pi/2) ├ + ├───┤├─────────────┤├──────────┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐├───────────┤ + ┤ H ├┤ P(2.0*x[1]) ├┤ RX(pi/2) ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├┤ RX(-pi/2) ├ + └───┘└─────────────┘└──────────┘└───┘└────────────────────────────────┘└───┘└───────────┘ The circuit contains ``reps`` repetitions of this transformation. @@ -70,28 +369,28 @@ class PauliFeatureMap(NLocal): Examples: >>> prep = PauliFeatureMap(2, reps=1, paulis=['ZZ']) - >>> print(prep) + >>> print(prep.decompose()) ┌───┐ - q_0: ┤ H ├──■───────────────────────────────────────■── - ├───┤┌─┴─┐┌─────────────────────────────────┐┌─┴─┐ - q_1: ┤ H ├┤ X ├┤ U1(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├ - └───┘└───┘└─────────────────────────────────┘└───┘ + q_0: ┤ H ├──■──────────────────────────────────────■── + ├───┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐ + q_1: ┤ H ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├ + └───┘└───┘└────────────────────────────────┘└───┘ >>> prep = PauliFeatureMap(2, reps=1, paulis=['Z', 'XX']) - >>> print(prep) - ┌───┐┌──────────────┐┌───┐ ┌───┐ - q_0: ┤ H ├┤ U1(2.0*x[0]) ├┤ H ├──■───────────────────────────────────────■──┤ H ├ - ├───┤├──────────────┤├───┤┌─┴─┐┌─────────────────────────────────┐┌─┴─┐├───┤ - q_1: ┤ H ├┤ U1(2.0*x[1]) ├┤ H ├┤ X ├┤ U1(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├┤ H ├ - └───┘└──────────────┘└───┘└───┘└─────────────────────────────────┘└───┘└───┘ + >>> print(prep.decompose()) + ┌───┐┌─────────────┐┌───┐ ┌───┐ + q_0: ┤ H ├┤ P(2.0*x[0]) ├┤ H ├──■──────────────────────────────────────■──┤ H ├ + ├───┤├─────────────┤├───┤┌─┴─┐┌────────────────────────────────┐┌─┴─┐├───┤ + q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ H ├┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├┤ H ├ + └───┘└─────────────┘└───┘└───┘└────────────────────────────────┘└───┘└───┘ >>> prep = PauliFeatureMap(2, reps=1, paulis=['ZY']) - >>> print(prep) - ┌───┐┌──────────┐ ┌───────────┐ - q_0: ┤ H ├┤ RX(pi/2) ├──■───────────────────────────────────────■──┤ RX(-pi/2) ├ - ├───┤└──────────┘┌─┴─┐┌─────────────────────────────────┐┌─┴─┐└───────────┘ - q_1: ┤ H ├────────────┤ X ├┤ U1(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├───────────── - └───┘ └───┘└─────────────────────────────────┘└───┘ + >>> print(prep.decompose()) + ┌───┐┌──────────┐ ┌───────────┐ + q_0: ┤ H ├┤ RX(pi/2) ├──■──────────────────────────────────────■──┤ RX(-pi/2) ├ + ├───┤└──────────┘┌─┴─┐┌────────────────────────────────┐┌─┴─┐└───────────┘ + q_1: ┤ H ├────────────┤ X ├┤ P(2.0*(pi - x[0])*(pi - x[1])) ├┤ X ├───────────── + └───┘ └───┘└────────────────────────────────┘└───┘ >>> from qiskit.circuit.library import EfficientSU2 >>> prep = PauliFeatureMap(3, reps=3, paulis=['Z', 'YY', 'ZXZ']) @@ -104,13 +403,18 @@ class PauliFeatureMap(NLocal): References: - - [1] Havlicek et al. Supervised learning with quantum enhanced feature spaces, `Nature 567, 209-212 (2019) `__. - """ + @deprecate_func( + since="1.3", + additional_msg=( + "Use the pauli_feature_map function as a replacement. Note that this will no longer " + "return a BlueprintCircuit, but just a plain QuantumCircuit." + ), + pending=True, + ) def __init__( self, feature_dimension: Optional[int] = None, @@ -161,6 +465,7 @@ def __init__( name=name, ) + self._prefix = parameter_prefix self._data_map_func = data_map_func or self_product self._paulis = paulis or ["Z", "ZZ"] self._alpha = alpha diff --git a/releasenotes/notes/rust-paulifm-1dc7b1c2dc756614.yaml b/releasenotes/notes/rust-paulifm-1dc7b1c2dc756614.yaml new file mode 100644 index 000000000000..103e792381ab --- /dev/null +++ b/releasenotes/notes/rust-paulifm-1dc7b1c2dc756614.yaml @@ -0,0 +1,16 @@ +--- +features_circuits: + - | + Added circuit library functions :func:`.pauli_feature_map`, :func:`.z_feature_map`, + :func:`.zz_feature_map` to construct Pauli feature map circuits. These functions + are approximately 8x faster than the current circuit library objects, + :class:`.PauliFeatureMap`, :class:`.ZFeatureMap`, and :class:`.ZZFeatureMap`, + and will replace them in the future. Note, that the new functions return a plain + :class:`.QuantumCircuit` instead of a :class:`.BlueprintCircuit`. + + The functions can be used as drop-in replacement:: + + from qiskit.circuit.library import pauli_feature_map, PauliFeatureMap + + fm = pauli_feature_map(20, paulis=["z", "xx", "yyy"]) + also_fm = PauliFeatureMap(20, paulis=["z", "xx", "yyy"]).decompose() diff --git a/test/python/circuit/library/test_pauli_feature_map.py b/test/python/circuit/library/test_pauli_feature_map.py index 0e15af654edd..5d61944d4032 100644 --- a/test/python/circuit/library/test_pauli_feature_map.py +++ b/test/python/circuit/library/test_pauli_feature_map.py @@ -19,7 +19,16 @@ from ddt import ddt, data, unpack from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector -from qiskit.circuit.library import PauliFeatureMap, ZFeatureMap, ZZFeatureMap, HGate +from qiskit.circuit.library import ( + PauliFeatureMap, + ZFeatureMap, + ZZFeatureMap, + HGate, + pauli_feature_map, + z_feature_map, + zz_feature_map, +) +from qiskit.exceptions import QiskitError from qiskit.quantum_info import Operator from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -295,5 +304,289 @@ def test_entanglement_not_specified(self): feat_map.count_ops() +@ddt +class TestPauliFeatureMap(QiskitTestCase): + """Test the Pauli feature map.""" + + @data((2, 3, ["X", "YY"]), (5, 2, ["ZZZXZ", "XZ"])) + @unpack + def test_num_parameters(self, num_qubits, reps, pauli_strings): + """Test the number of parameters equals the number of qubits, independent of reps.""" + encoding = pauli_feature_map(num_qubits, paulis=pauli_strings, reps=reps) + self.assertEqual(encoding.num_parameters, num_qubits) + + def test_pauli_zz_with_barriers(self): + """Test the generation of Pauli blocks.""" + encoding = QuantumCircuit(3) + encoding.compose(pauli_feature_map(3, paulis=["zz"], insert_barriers=True), inplace=True) + + params = encoding.parameters + + def zz(circuit, i, j): + circuit.cx(i, j) + circuit.p(2 * (np.pi - params[i]) * (np.pi - params[j]), j) + circuit.cx(i, j) + + ref = QuantumCircuit(3) + for i in range(2): + ref.h(range(3)) + ref.barrier() + zz(ref, 0, 1) + zz(ref, 0, 2) + zz(ref, 1, 2) + if i == 0: + ref.barrier() + + self.assertEqual(ref, encoding) + + def test_pauli_xyz(self): + """Test the generation of Pauli blocks.""" + encoding = QuantumCircuit(3) + encoding.compose(pauli_feature_map(3, paulis=["xyz"], reps=1), inplace=True) + # encoding = PauliFeatureMap(3, paulis=["XYZ"], reps=1).decompose() + + params = encoding.parameters + + # q_0: ─────────────■────────────────────────■────────────── + # ┌─────────┐┌─┴─┐ ┌─┴─┐┌──────────┐ + # q_1: ┤ Rx(π/2) ├┤ X ├──■──────────────■──┤ X ├┤ Rx(-π/2) ├ + # └──┬───┬──┘└───┘┌─┴─┐┌────────┐┌─┴─┐├───┤└──────────┘ + # q_2: ───┤ H ├────────┤ X ├┤ P(2.8) ├┤ X ├┤ H ├──────────── + # └───┘ └───┘└────────┘└───┘└───┘ + # X on the most-significant, bottom qubit, Z on the top + ref = QuantumCircuit(3) + ref.h(range(3)) + ref.h(2) + ref.rx(np.pi / 2, 1) + ref.cx(0, 1) + ref.cx(1, 2) + ref.p(2 * np.prod([np.pi - p for p in params]), 2) + ref.cx(1, 2) + ref.cx(0, 1) + ref.rx(-np.pi / 2, 1) + ref.h(2) + + self.assertEqual(ref, encoding) + + def test_first_order_circuit(self): + """Test a first order expansion circuit.""" + times = [0.2, 1, np.pi, -1.2] + encoding = z_feature_map(4, reps=3).assign_parameters(times) + + # ┌───┐ ┌────────┐┌───┐ ┌────────┐┌───┐ ┌────────┐ + # q_0: ┤ H ├─┤ P(0.4) ├┤ H ├─┤ P(0.4) ├┤ H ├─┤ P(0.4) ├ + # ├───┤ └┬──────┬┘├───┤ └┬──────┬┘├───┤ └┬──────┬┘ + # q_1: ┤ H ├──┤ P(2) ├─┤ H ├──┤ P(2) ├─┤ H ├──┤ P(2) ├─ + # ├───┤ ┌┴──────┤ ├───┤ ┌┴──────┤ ├───┤ ┌┴──────┤ + # q_2: ┤ H ├─┤ P(2π) ├─┤ H ├─┤ P(2π) ├─┤ H ├─┤ P(2π) ├─ + # ├───┤┌┴───────┴┐├───┤┌┴───────┴┐├───┤┌┴───────┴┐ + # q_3: ┤ H ├┤ P(-2.4) ├┤ H ├┤ P(-2.4) ├┤ H ├┤ P(-2.4) ├ + # └───┘└─────────┘└───┘└─────────┘└───┘└─────────┘ + ref = QuantumCircuit(4) + for _ in range(3): + ref.h([0, 1, 2, 3]) + for i in range(4): + ref.p(2 * times[i], i) + + self.assertTrue(Operator(encoding).equiv(ref)) + + def test_second_order_circuit(self): + """Test a second order expansion circuit.""" + times = [0.2, 1, np.pi] + encoding = zz_feature_map(3, reps=2).assign_parameters(times) + + def zz_evolution(circuit, qubit1, qubit2): + time = (np.pi - times[qubit1]) * (np.pi - times[qubit2]) + circuit.cx(qubit1, qubit2) + circuit.p(2 * time, qubit2) + circuit.cx(qubit1, qubit2) + + # ┌───┐┌────────┐ ┌───┐┌────────┐» + # q_0: ┤ H ├┤ P(0.4) ├──■─────────────────■────■────────────■──┤ H ├┤ P(0.4) ├» + # ├───┤└┬──────┬┘┌─┴─┐┌───────────┐┌─┴─┐ │ │ └───┘└────────┘» + # q_1: ┤ H ├─┤ P(2) ├─┤ X ├┤ P(12.599) ├┤ X ├──┼────────────┼────■────────────» + # ├───┤┌┴──────┤ └───┘└───────────┘└───┘┌─┴─┐┌──────┐┌─┴─┐┌─┴─┐ ┌──────┐ » + # q_2: ┤ H ├┤ P(2π) ├────────────────────────┤ X ├┤ P(0) ├┤ X ├┤ X ├─┤ P(0) ├─» + # └───┘└───────┘ └───┘└──────┘└───┘└───┘ └──────┘ » + # « » + # «q_0: ─────────────────────■─────────────────■────■────────────■───────────────» + # « ┌───┐ ┌──────┐┌─┴─┐┌───────────┐┌─┴─┐ │ │ » + # «q_1: ──■──┤ H ├─┤ P(2) ├┤ X ├┤ P(12.599) ├┤ X ├──┼────────────┼────■──────────» + # « ┌─┴─┐├───┤┌┴──────┤└───┘└───────────┘└───┘┌─┴─┐┌──────┐┌─┴─┐┌─┴─┐┌──────┐» + # «q_2: ┤ X ├┤ H ├┤ P(2π) ├───────────────────────┤ X ├┤ P(0) ├┤ X ├┤ X ├┤ P(0) ├» + # « └───┘└───┘└───────┘ └───┘└──────┘└───┘└───┘└──────┘» + # « + # «q_0: ───── + # « + # «q_1: ──■── + # « ┌─┴─┐ + # «q_2: ┤ X ├ + # « └───┘ + ref = QuantumCircuit(3) + for _ in range(2): + ref.h([0, 1, 2]) + for i in range(3): + ref.p(2 * times[i], i) + zz_evolution(ref, 0, 1) + zz_evolution(ref, 0, 2) + zz_evolution(ref, 1, 2) + + self.assertTrue(Operator(encoding).equiv(ref)) + + @combine(entanglement=["linear", "reverse_linear", "pairwise"]) + def test_zz_entanglement(self, entanglement): + """Test the ZZ feature map works with pairwise, linear and reverse_linear entanglement.""" + num_qubits = 5 + encoding = zz_feature_map(num_qubits, entanglement=entanglement, reps=1) + ops = encoding.count_ops() + expected_ops = {"h": num_qubits, "p": 2 * num_qubits - 1, "cx": 2 * (num_qubits - 1)} + self.assertEqual(ops, expected_ops) + + def test_pauli_alpha(self): + """Test Pauli rotation factor (getter, setter).""" + alpha = 1.234 + + # this is needed as the outcoming Rust circuit has no qreg + encoding = QuantumCircuit(1) + encoding.compose(pauli_feature_map(1, alpha=alpha, paulis=["z"], reps=1), inplace=True) + + ref = QuantumCircuit(1) + ref.h(0) + ref.p(alpha * encoding.parameters[0], 0) + + self.assertEqual(ref, encoding) + + def test_zzfeaturemap_raises_if_too_small(self): + """Test the ``ZZFeatureMap`` raises an error if the number of qubits is smaller than 2.""" + with self.assertRaises(QiskitError): + _ = zz_feature_map(1) + + def test_dict_entanglement(self): + """Test passing the entanglement as dictionary.""" + entanglement = {1: [(0,), (2,)], 2: [(1, 2)], 3: [(0, 1, 2)]} + circuit = QuantumCircuit(3) + circuit.compose( + pauli_feature_map(3, reps=1, paulis=["z", "xx", "yyy"], entanglement=entanglement), + inplace=True, + ) + x = circuit.parameters + + ref = QuantumCircuit(3) + ref.h(ref.qubits) + + ref.p(2 * x[0], 0) + ref.p(2 * x[2], 2) + + ref.h([1, 2]) + ref.cx(1, 2) + ref.p(2 * np.prod([np.pi - xi for xi in [x[1], x[2]]]), 2) + ref.cx(1, 2) + ref.h([1, 2]) + + ref.rx(np.pi / 2, range(3)) + ref.cx(0, 1) + ref.cx(1, 2) + ref.p(2 * np.prod([np.pi - xi for xi in x]), 2) + ref.cx(1, 2) + ref.cx(0, 1) + ref.rx(-np.pi / 2, range(3)) + + self.assertEqual(ref, circuit) + + def test_invalid_entanglement(self): + """Test if a ValueError is raised when an invalid entanglement is passed""" + n_qubits = 3 + entanglement = { + 1: [(0, 1), (2,)], + 2: [(0, 1), (1, 2)], + 3: [(0, 1, 2)], + } + + with self.assertRaises(QiskitError): + _ = pauli_feature_map( + n_qubits, reps=2, paulis=["Z", "ZZ", "ZZZ"], entanglement=entanglement + ) + + def test_entanglement_not_specified(self): + """Test if an error is raised when entanglement is not explicitly specified for + all n-qubit pauli blocks""" + n_qubits = 3 + entanglement = { + 1: [(0, 1), (2,)], + 3: [(0, 1, 2)], + } + with self.assertRaises(QiskitError): + _ = pauli_feature_map( + n_qubits, reps=2, paulis=["Z", "ZZ", "ZZZ"], entanglement=entanglement + ) + + def test_parameter_prefix(self): + """Test the Parameter prefix""" + encoding_pauli = pauli_feature_map( + feature_dimension=2, reps=2, paulis=["ZY"], parameter_prefix="p" + ) + encoding_z = z_feature_map(feature_dimension=2, reps=2, parameter_prefix="q") + encoding_zz = zz_feature_map(feature_dimension=2, reps=2, parameter_prefix="r") + x = ParameterVector("x", 2) + y = Parameter("y") + + self.assertEqual( + str(encoding_pauli.parameters), + "ParameterView([ParameterVectorElement(p[0]), ParameterVectorElement(p[1])])", + ) + self.assertEqual( + str(encoding_z.parameters), + "ParameterView([ParameterVectorElement(q[0]), ParameterVectorElement(q[1])])", + ) + self.assertEqual( + str(encoding_zz.parameters), + "ParameterView([ParameterVectorElement(r[0]), ParameterVectorElement(r[1])])", + ) + + encoding_pauli_param_x = encoding_pauli.assign_parameters(x) + encoding_z_param_x = encoding_z.assign_parameters(x) + encoding_zz_param_x = encoding_zz.assign_parameters(x) + + self.assertEqual( + str(encoding_pauli_param_x.parameters), + "ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])])", + ) + self.assertEqual( + str(encoding_z_param_x.parameters), + "ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])])", + ) + self.assertEqual( + str(encoding_zz_param_x.parameters), + "ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])])", + ) + + encoding_pauli_param_y = encoding_pauli.assign_parameters([1, y]) + encoding_z_param_y = encoding_z.assign_parameters([1, y]) + encoding_zz_param_y = encoding_zz.assign_parameters([1, y]) + + self.assertEqual(str(encoding_pauli_param_y.parameters), "ParameterView([Parameter(y)])") + self.assertEqual(str(encoding_z_param_y.parameters), "ParameterView([Parameter(y)])") + self.assertEqual(str(encoding_zz_param_y.parameters), "ParameterView([Parameter(y)])") + + def test_custom_data_mapping(self): + """Test passing a custom data mapping function.""" + + def my_mapping(x): + return 42 if len(x) == 1 else np.sum(x) + + encoding = QuantumCircuit(2) + encoding.compose(zz_feature_map(2, reps=1, data_map_func=my_mapping), inplace=True) + + params = encoding.parameters + ref = QuantumCircuit(2) + ref.h(range(2)) + ref.p(2 * 42, range(2)) + ref.cx(0, 1) + ref.p(2 * (params[0] + params[1]), 1) + ref.cx(0, 1) + + self.assertEqual(ref, encoding) + + if __name__ == "__main__": unittest.main() From b083de6cdefac86c47171f4b8e4ef2913979bebc Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 12 Sep 2024 11:00:04 -0400 Subject: [PATCH 78/85] Revert version number back to 1.3.0 after beta pre-release (#13142) Now that the 1.3.0b1 pre-release has been published this commit reverts the version number back to 1.3.0 to differentiate development builds from the published pre-release. --- Cargo.lock | 269 ++++++++++++++++++++++++--------------------- docs/conf.py | 2 +- qiskit/VERSION.txt | 2 +- 3 files changed, 146 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d00620630e79..d73b21266dab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,9 +82,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" @@ -94,9 +94,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -129,13 +129,13 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -184,24 +184,24 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" [[package]] name = "cov-mark" -version = "2.0.0-pre.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" +checksum = "0570650661aa447e7335f1d5e4f499d8e58796e617bedc9267d971e51c8b49d4" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -281,20 +281,20 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -323,7 +323,7 @@ checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -334,7 +334,7 @@ checksum = "5322a90066ddae2b705096eb9e10c465c0498ae93bf9bdd6437415327c88e3bb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -533,9 +533,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -580,11 +580,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "indexmap" @@ -605,9 +611,9 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ "hermit-abi", "libc", @@ -655,9 +661,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -677,9 +683,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matrixcompare" @@ -699,9 +705,9 @@ checksum = "b0bdabb30db18805d5290b3da7ceaccbddba795620b86c02145d688e04900a73" [[package]] name = "matrixmultiply" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ "autocfg", "rawpointer", @@ -709,9 +715,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -969,9 +975,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -987,20 +993,20 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", "thiserror", @@ -1009,9 +1015,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" dependencies = [ "pest", "pest_generator", @@ -1019,22 +1025,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" dependencies = [ "once_cell", "pest", @@ -1053,21 +1059,24 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "priority-queue" -version = "2.0.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c501afe3a2e25c9bd219aa56ec1e04cdb3fcdd763055be268778c13fa82c1f" +checksum = "560bcab673ff7f6ca9e270c17bf3affd8a05e3bd9207f123b0d45076fd8197e8" dependencies = [ "autocfg", "equivalent", @@ -1128,7 +1137,7 @@ checksum = "d315b3197b780e4873bc0e11251cb56a33f65a6032a3d39b8d1405c255513766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1196,7 +1205,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1205,11 +1214,11 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1296,9 +1305,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1426,11 +1435,11 @@ checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -1483,9 +1492,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rustworkx-core" @@ -1530,22 +1539,22 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.200" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1567,9 +1576,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smol_str" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" dependencies = [ "serde", ] @@ -1587,9 +1596,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.76" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1602,7 +1611,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "enum-as-inner", "libc", @@ -1612,9 +1621,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "text-size" @@ -1639,7 +1648,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1662,27 +1671,27 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unindent" @@ -1692,9 +1701,9 @@ checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -1730,11 +1739,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1773,7 +1782,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1793,18 +1811,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1815,9 +1833,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1827,9 +1845,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1839,15 +1857,15 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1857,9 +1875,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1869,9 +1887,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1881,9 +1899,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1893,9 +1911,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "xshell" @@ -1920,20 +1938,21 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] diff --git a/docs/conf.py b/docs/conf.py index 493dd58de83c..a84a1ff691bf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,7 +32,7 @@ # The short X.Y version version = "1.3" # The full version, including alpha/beta/rc tags -release = "1.3.0b1" +release = "1.3.0" language = "en" diff --git a/qiskit/VERSION.txt b/qiskit/VERSION.txt index 94bfba8ed4ed..f0bb29e76388 100644 --- a/qiskit/VERSION.txt +++ b/qiskit/VERSION.txt @@ -1 +1 @@ -1.3.0b1 +1.3.0 From 4c88a71237ccfc528e8a0b3704a53a3375cab8be Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 12 Sep 2024 15:28:26 -0400 Subject: [PATCH 79/85] Oxidize dag_to_circuit() (#13126) * Oxidize dag_to_circuit() This commit migrates the dag_to_circuit() converter function implementation to rust. The core of this is having a DAGCircuit to CircuitData converter function in rust. To do this efficiently we just copy the BitDatas and Interners to the new circuit data object being created and then just iterate over all the packed instructions in the circuit. To facilitate this a new constructor for CircuitData is added that takes an iterator of PackedInstructions and the BitDatas and Interners and builds a new circuit data from that. * Apply suggestions from code review Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * Update crates/circuit/src/converters.rs Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * Update crates/circuit/src/converters.rs Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> * Use immutable access methods instead of relying on public fields * Add docstring to the new CircuitData constructor method --------- Co-authored-by: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> --- crates/circuit/src/circuit_data.rs | 57 +++++++++++++++++++++++++++++ crates/circuit/src/converters.rs | 51 +++++++++++++++++++++++++- crates/circuit/src/dag_circuit.rs | 4 +- qiskit/converters/dag_to_circuit.py | 6 ++- 4 files changed, 113 insertions(+), 5 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index da49f9edc605..b367a6877c11 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -166,6 +166,63 @@ impl CircuitData { Ok(res) } + /// A constructor for CircuitData from an iterator of PackedInstruction objects + /// + /// This is tpically useful when iterating over a CircuitData or DAGCircuit + /// to construct a new CircuitData from the iterator of PackedInstructions. As + /// such it requires that you have `BitData` and `Interner` objects to run. If + /// you just wish to build a circuit data from an iterator of instructions + /// the `from_packed_operations` or `from_standard_gates` constructor methods + /// are a better choice + /// + /// # Args + /// + /// * py: A GIL handle this is needed to instantiate Qubits in Python space + /// * qubits: The BitData to use for the new circuit's qubits + /// * clbits: The BitData to use for the new circuit's clbits + /// * qargs_interner: The interner for Qubit objects in the circuit. This must + /// contain all the Interned indices stored in the + /// PackedInstructions from `instructions` + /// * cargs_interner: The interner for Clbit objects in the circuit. This must + /// contain all the Interned indices stored in the + /// PackedInstructions from `instructions` + /// * Instructions: An iterator with items of type: `PyResult` + /// that contais the instructions to insert in iterator order to the new + /// CircuitData. This returns a `PyResult` to facilitate the case where + /// you need to make a python copy (such as with `PackedOperation::py_deepcopy()`) + /// of the operation while iterating for constructing the new `CircuitData`. An + /// example of this use case is in `qiskit_circuit::converters::dag_to_circuit`. + /// * global_phase: The global phase value to use for the new circuit. + pub fn from_packed_instructions( + py: Python, + qubits: BitData, + clbits: BitData, + qargs_interner: Interner<[Qubit]>, + cargs_interner: Interner<[Clbit]>, + instructions: I, + global_phase: Param, + ) -> PyResult + where + I: IntoIterator>, + { + let instruction_iter = instructions.into_iter(); + let mut res = CircuitData { + data: Vec::with_capacity(instruction_iter.size_hint().0), + qargs_interner, + cargs_interner, + qubits, + clbits, + param_table: ParameterTable::new(), + global_phase, + }; + + for inst in instruction_iter { + res.data.push(inst?); + res.track_instruction_parameters(py, res.data.len() - 1)?; + } + Ok(res) + } + /// An alternate constructor to build a new `CircuitData` from an iterator /// of standard gates. This can be used to build a circuit from a sequence /// of standard gates, such as for a `StandardGate` definition or circuit diff --git a/crates/circuit/src/converters.rs b/crates/circuit/src/converters.rs index ab9d4bce0475..37ba83ae5173 100644 --- a/crates/circuit/src/converters.rs +++ b/crates/circuit/src/converters.rs @@ -10,6 +10,9 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. +#[cfg(feature = "cache_pygates")] +use std::cell::OnceCell; + use ::pyo3::prelude::*; use hashbrown::HashMap; use pyo3::{ @@ -17,7 +20,9 @@ use pyo3::{ types::{PyDict, PyList}, }; -use crate::{circuit_data::CircuitData, dag_circuit::DAGCircuit}; +use crate::circuit_data::CircuitData; +use crate::dag_circuit::{DAGCircuit, NodeType}; +use crate::packed_instruction::PackedInstruction; /// An extractable representation of a QuantumCircuit reserved only for /// conversion purposes. @@ -85,7 +90,51 @@ pub fn circuit_to_dag( ) } +#[pyfunction(signature = (dag, copy_operations = true))] +pub fn dag_to_circuit( + py: Python, + dag: &DAGCircuit, + copy_operations: bool, +) -> PyResult { + CircuitData::from_packed_instructions( + py, + dag.qubits().clone(), + dag.clbits().clone(), + dag.qargs_interner().clone(), + dag.cargs_interner().clone(), + dag.topological_op_nodes()?.map(|node_index| { + let NodeType::Operation(ref instr) = dag.dag()[node_index] else { + unreachable!( + "The received node from topological_op_nodes() is not an Operation node." + ) + }; + if copy_operations { + let op = instr.op.py_deepcopy(py, None)?; + Ok(PackedInstruction { + op, + qubits: instr.qubits, + clbits: instr.clbits, + params: Some(Box::new( + instr + .params_view() + .iter() + .map(|param| param.clone_ref(py)) + .collect(), + )), + extra_attrs: instr.extra_attrs.clone(), + #[cfg(feature = "cache_pygates")] + py_op: OnceCell::new(), + }) + } else { + Ok(instr.clone()) + } + }), + dag.get_global_phase(), + ) +} + pub fn converters(m: &Bound) -> PyResult<()> { m.add_function(wrap_pyfunction!(circuit_to_dag, m)?)?; + m.add_function(wrap_pyfunction!(dag_to_circuit, m)?)?; Ok(()) } diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index d872806c5315..0e944789d307 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -782,7 +782,7 @@ impl DAGCircuit { /// Return the global phase of the circuit. #[getter] - fn get_global_phase(&self) -> Param { + pub fn get_global_phase(&self) -> Param { self.global_phase.clone() } @@ -6375,7 +6375,7 @@ impl DAGCircuit { params: (!new_op.params.is_empty()).then(|| Box::new(new_op.params)), extra_attrs: new_op.extra_attrs, #[cfg(feature = "cache_pygates")] - py_op: py_op, + py_op, }; let new_index = self.dag.add_node(NodeType::Operation(inst)); self.dag.add_edge(source, new_index, weight.clone()); diff --git a/qiskit/converters/dag_to_circuit.py b/qiskit/converters/dag_to_circuit.py index 47adee456380..84ea6ef0fd24 100644 --- a/qiskit/converters/dag_to_circuit.py +++ b/qiskit/converters/dag_to_circuit.py @@ -13,6 +13,7 @@ """Helper function for converting a dag to a circuit.""" from qiskit.circuit import QuantumCircuit +from qiskit._accelerate.converters import dag_to_circuit as dag_to_circuit_rs def dag_to_circuit(dag, copy_operations=True): @@ -54,6 +55,8 @@ def dag_to_circuit(dag, copy_operations=True): """ name = dag.name or None + + circuit_data = dag_to_circuit_rs(dag, copy_operations) circuit = QuantumCircuit( dag.qubits, dag.clbits, @@ -69,8 +72,7 @@ def dag_to_circuit(dag, copy_operations=True): circuit.metadata = dag.metadata circuit.calibrations = dag.calibrations - for node in dag.topological_op_nodes(): - circuit._append(node._to_circuit_instruction(deepcopy=copy_operations)) + circuit._data = circuit_data circuit.duration = dag.duration circuit.unit = dag.unit From c655acb51bf41d70e6c22cdf176f3cad6334198d Mon Sep 17 00:00:00 2001 From: Kevin Hartman Date: Thu, 12 Sep 2024 16:23:26 -0400 Subject: [PATCH 80/85] Move `Option>` into `ExtraInstructionAttributes`. (#13127) * Move Option> into ExtraInstructionAttributes. Previously, CircuitInstruction and PackedInstruction held the ExtraInstructionAttributes struct within an Option>. By putting the Option> inside ExtraInstructionAttributes, we can use the struct itself to manage its memory and provide access to the attributes behind a nicer interface. The size of ExtraInstructionAttributes should be the same size as the old Option>, so this should not have memory implications. * Address review comments. - Use tuple struct. - Use 'Attributes' over 'Attrs'. - Add doc comment for internal 'ExtraAttributes' struct. - Add doc comments for methods. - Add setters for unit and duration. * Fix performance regression from unnecessary dict creation. --- crates/accelerate/src/commutation_analysis.rs | 4 +- crates/accelerate/src/commutation_checker.rs | 20 +- crates/circuit/src/circuit_data.rs | 17 +- crates/circuit/src/circuit_instruction.rs | 205 +++++++++++++----- crates/circuit/src/dag_circuit.rs | 111 ++-------- crates/circuit/src/dag_node.rs | 43 +--- crates/circuit/src/operations.rs | 18 +- crates/circuit/src/packed_instruction.rs | 12 +- 8 files changed, 209 insertions(+), 221 deletions(-) diff --git a/crates/accelerate/src/commutation_analysis.rs b/crates/accelerate/src/commutation_analysis.rs index e8b47658b9f4..a29c648a5f81 100644 --- a/crates/accelerate/src/commutation_analysis.rs +++ b/crates/accelerate/src/commutation_analysis.rs @@ -95,12 +95,12 @@ pub(crate) fn analyze_commutations_inner( py, &op1, params1, - packed_inst0.extra_attrs.as_deref(), + &packed_inst0.extra_attrs, qargs1, cargs1, &op2, params2, - packed_inst1.extra_attrs.as_deref(), + &packed_inst1.extra_attrs, qargs2, cargs2, MAX_NUM_QUBITS, diff --git a/crates/accelerate/src/commutation_checker.rs b/crates/accelerate/src/commutation_checker.rs index c7fbd03a2afe..b6e61fcf3f6d 100644 --- a/crates/accelerate/src/commutation_checker.rs +++ b/crates/accelerate/src/commutation_checker.rs @@ -121,12 +121,12 @@ impl CommutationChecker { py, &op1.instruction.operation.view(), &op1.instruction.params, - op1.instruction.extra_attrs.as_deref(), + &op1.instruction.extra_attrs, &qargs1, &cargs1, &op2.instruction.operation.view(), &op2.instruction.params, - op2.instruction.extra_attrs.as_deref(), + &op2.instruction.extra_attrs, &qargs2, &cargs2, max_num_qubits, @@ -162,12 +162,12 @@ impl CommutationChecker { py, &op1.operation.view(), &op1.params, - op1.extra_attrs.as_deref(), + &op1.extra_attrs, &qargs1, &cargs1, &op2.operation.view(), &op2.params, - op2.extra_attrs.as_deref(), + &op2.extra_attrs, &qargs2, &cargs2, max_num_qubits, @@ -232,12 +232,12 @@ impl CommutationChecker { py: Python, op1: &OperationRef, params1: &[Param], - attrs1: Option<&ExtraInstructionAttributes>, + attrs1: &ExtraInstructionAttributes, qargs1: &[Qubit], cargs1: &[Clbit], op2: &OperationRef, params2: &[Param], - attrs2: Option<&ExtraInstructionAttributes>, + attrs2: &ExtraInstructionAttributes, qargs2: &[Qubit], cargs2: &[Clbit], max_num_qubits: u32, @@ -494,20 +494,20 @@ impl CommutationChecker { fn commutation_precheck( op1: &OperationRef, params1: &[Param], - attrs1: Option<&ExtraInstructionAttributes>, + attrs1: &ExtraInstructionAttributes, qargs1: &[Qubit], cargs1: &[Clbit], op2: &OperationRef, params2: &[Param], - attrs2: Option<&ExtraInstructionAttributes>, + attrs2: &ExtraInstructionAttributes, qargs2: &[Qubit], cargs2: &[Clbit], max_num_qubits: u32, ) -> Option { if op1.control_flow() || op2.control_flow() - || attrs1.is_some_and(|attr| attr.condition.is_some()) - || attrs2.is_some_and(|attr| attr.condition.is_some()) + || attrs1.condition().is_some() + || attrs2.condition().is_some() { return Some(false); } diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index b367a6877c11..0308bd8dfb8b 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -14,7 +14,9 @@ use std::cell::OnceCell; use crate::bit_data::BitData; -use crate::circuit_instruction::{CircuitInstruction, OperationFromPython}; +use crate::circuit_instruction::{ + CircuitInstruction, ExtraInstructionAttributes, OperationFromPython, +}; use crate::imports::{ANNOTATED_OPERATION, CLBIT, QUANTUM_CIRCUIT, QUBIT}; use crate::interner::{Interned, Interner}; use crate::operations::{Operation, OperationRef, Param, StandardGate}; @@ -157,7 +159,7 @@ impl CircuitData { qubits, clbits, params, - extra_attrs: None, + extra_attrs: ExtraInstructionAttributes::default(), #[cfg(feature = "cache_pygates")] py_op: OnceCell::new(), }); @@ -266,7 +268,7 @@ impl CircuitData { qubits, clbits: no_clbit_index, params, - extra_attrs: None, + extra_attrs: ExtraInstructionAttributes::default(), #[cfg(feature = "cache_pygates")] py_op: OnceCell::new(), }); @@ -324,7 +326,7 @@ impl CircuitData { qubits, clbits: no_clbit_index, params, - extra_attrs: None, + extra_attrs: ExtraInstructionAttributes::default(), #[cfg(feature = "cache_pygates")] py_op: OnceCell::new(), }); @@ -683,12 +685,7 @@ impl CircuitData { #[pyo3(signature = (func))] pub fn map_nonstandard_ops(&mut self, py: Python<'_>, func: &Bound) -> PyResult<()> { for inst in self.data.iter_mut() { - if inst.op.try_standard_gate().is_some() - && !inst - .extra_attrs - .as_ref() - .is_some_and(|attrs| attrs.condition.is_some()) - { + if inst.op.try_standard_gate().is_some() && inst.extra_attrs.condition().is_none() { continue; } let py_op = func.call1((inst.unpack_py_op(py)?,))?; diff --git a/crates/circuit/src/circuit_instruction.rs b/crates/circuit/src/circuit_instruction.rs index 463f3352aa92..a56aee2c6137 100644 --- a/crates/circuit/src/circuit_instruction.rs +++ b/crates/circuit/src/circuit_instruction.rs @@ -30,18 +30,23 @@ use crate::operations::{ }; use crate::packed_instruction::PackedOperation; -/// These are extra mutable attributes for a circuit instruction's state. In general we don't -/// typically deal with this in rust space and the majority of the time they're not used in Python -/// space either. To save memory these are put in a separate struct and are stored inside a -/// `Box` on `CircuitInstruction` and `PackedInstruction`. +/// This is a private struct used to hold the actual attributes, which we store +/// on the heap using the [Box] within [ExtraInstructionAttributes]. #[derive(Debug, Clone)] -pub struct ExtraInstructionAttributes { - pub label: Option, - pub duration: Option, - pub unit: Option, - pub condition: Option, +struct ExtraAttributes { + label: Option, + duration: Option, + unit: Option, + condition: Option, } +/// Extra mutable attributes for a circuit instruction's state. In general we don't +/// typically deal with this in rust space and the majority of the time they're not used in Python +/// space either. To save memory, the attributes are stored inside a `Box` internally, so this +/// struct is no larger than that. +#[derive(Default, Debug, Clone)] +pub struct ExtraInstructionAttributes(Option>); + impl ExtraInstructionAttributes { /// Construct a new set of the extra attributes if any of the elements are not `None`, or return /// `None` if there is no need for an object. @@ -51,25 +56,32 @@ impl ExtraInstructionAttributes { duration: Option>, unit: Option, condition: Option>, - ) -> Option { - if label.is_some() || duration.is_some() || unit.is_some() || condition.is_some() { - Some(Self { - label, - duration, - unit, - condition, - }) - } else { - None - } + ) -> Self { + ExtraInstructionAttributes( + if label.is_some() || duration.is_some() || unit.is_some() || condition.is_some() { + Some(Box::new(ExtraAttributes { + label, + duration, + unit, + condition, + })) + } else { + None + }, + ) } - /// Get the Python-space version of the stored `unit`. This evalutes the Python-space default - /// (`"dt"`) value if we're storing a `None`. + /// Get the Python-space version of the stored `unit`. + /// This evaluates the Python-space default (`"dt"`) value if we're storing a `None`. pub fn py_unit(&self, py: Python) -> Py { - self.unit + self.0 .as_deref() - .map(|unit| <&str as IntoPy>>::into_py(unit, py)) + .and_then(|attrs| { + attrs + .unit + .as_deref() + .map(|unit| <&str as IntoPy>>::into_py(unit, py)) + }) .unwrap_or_else(|| Self::default_unit(py).clone().unbind()) } @@ -77,6 +89,106 @@ impl ExtraInstructionAttributes { pub fn default_unit(py: Python) -> &Bound { intern!(py, "dt") } + + /// Get the stored label attribute. + pub fn label(&self) -> Option<&str> { + self.0.as_deref().and_then(|attrs| attrs.label.as_deref()) + } + + /// Set the stored label attribute, or clear it if `label` is `None`. + pub fn set_label(&mut self, label: Option) { + if let Some(attrs) = &mut self.0 { + attrs.label = label; + self.shrink_if_empty(); + return; + } + if label.is_some() { + self.0 = Some(Box::new(ExtraAttributes { + label, + duration: None, + unit: None, + condition: None, + })) + } + } + + /// Get the stored duration attribute. + pub fn duration(&self) -> Option<&PyObject> { + self.0.as_deref().and_then(|attrs| attrs.duration.as_ref()) + } + + /// Set the stored duration attribute, or clear it if `duration` is `None`. + pub fn set_duration(&mut self, duration: Option) { + if let Some(attrs) = &mut self.0 { + attrs.duration = duration; + self.shrink_if_empty(); + return; + } + if duration.is_some() { + self.0 = Some(Box::new(ExtraAttributes { + label: None, + duration, + unit: None, + condition: None, + })) + } + } + + /// Get the unit attribute. + pub fn unit(&self) -> Option<&str> { + self.0.as_deref().and_then(|attrs| attrs.unit.as_deref()) + } + + /// Set the stored unit attribute, or clear it if `unit` is `None`. + pub fn set_unit(&mut self, unit: Option) { + if let Some(attrs) = &mut self.0 { + attrs.unit = unit; + self.shrink_if_empty(); + return; + } + if unit.is_some() { + self.0 = Some(Box::new(ExtraAttributes { + label: None, + duration: None, + unit, + condition: None, + })) + } + } + + /// Get the condition attribute. + pub fn condition(&self) -> Option<&PyObject> { + self.0.as_deref().and_then(|attrs| attrs.condition.as_ref()) + } + + /// Set the stored condition attribute, or clear it if `condition` is `None`. + pub fn set_condition(&mut self, condition: Option) { + if let Some(attrs) = &mut self.0 { + attrs.condition = condition; + self.shrink_if_empty(); + return; + } + if condition.is_some() { + self.0 = Some(Box::new(ExtraAttributes { + label: None, + duration: None, + unit: None, + condition, + })) + } + } + + fn shrink_if_empty(&mut self) { + if let Some(attrs) = &self.0 { + if attrs.label.is_none() + && attrs.duration.is_none() + && attrs.unit.is_none() + && attrs.condition.is_none() + { + self.0 = None; + } + } + } } /// A single instruction in a :class:`.QuantumCircuit`, comprised of the :attr:`operation` and @@ -122,7 +234,7 @@ pub struct CircuitInstruction { #[pyo3(get)] pub clbits: Py, pub params: SmallVec<[Param; 3]>, - pub extra_attrs: Option>, + pub extra_attrs: ExtraInstructionAttributes, #[cfg(feature = "cache_pygates")] pub py_op: OnceCell>, } @@ -146,9 +258,7 @@ impl CircuitInstruction { } pub fn condition(&self) -> Option<&PyObject> { - self.extra_attrs - .as_ref() - .and_then(|args| args.condition.as_ref()) + self.extra_attrs.condition() } } @@ -189,14 +299,7 @@ impl CircuitInstruction { qubits: as_tuple(py, qubits)?.unbind(), clbits: PyTuple::empty_bound(py).unbind(), params, - extra_attrs: label.map(|label| { - Box::new(ExtraInstructionAttributes { - label: Some(label), - duration: None, - unit: None, - condition: None, - }) - }), + extra_attrs: ExtraInstructionAttributes::new(label, None, None, None), #[cfg(feature = "cache_pygates")] py_op: OnceCell::new(), }) @@ -227,7 +330,7 @@ impl CircuitInstruction { let out = match self.operation.view() { OperationRef::Standard(standard) => standard - .create_py_op(py, Some(&self.params), self.extra_attrs.as_deref())? + .create_py_op(py, Some(&self.params), &self.extra_attrs)? .into_any(), OperationRef::Gate(gate) => gate.gate.clone_ref(py), OperationRef::Instruction(instruction) => instruction.instruction.clone_ref(py), @@ -261,37 +364,24 @@ impl CircuitInstruction { #[getter] fn label(&self) -> Option<&str> { - self.extra_attrs - .as_ref() - .and_then(|attrs| attrs.label.as_deref()) + self.extra_attrs.label() } #[getter] fn get_condition(&self, py: Python) -> Option { - self.extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref().map(|x| x.clone_ref(py))) + self.extra_attrs.condition().map(|x| x.clone_ref(py)) } #[getter] fn duration(&self, py: Python) -> Option { - self.extra_attrs - .as_ref() - .and_then(|attrs| attrs.duration.as_ref().map(|x| x.clone_ref(py))) + self.extra_attrs.duration().map(|x| x.clone_ref(py)) } #[getter] fn unit(&self, py: Python) -> Py { // Python space uses `"dt"` as the default, whereas we simply don't store the extra // attributes at all if they're none. - self.extra_attrs - .as_ref() - .map(|attrs| attrs.py_unit(py)) - .unwrap_or_else(|| { - ExtraInstructionAttributes::default_unit(py) - .clone() - .unbind() - }) + self.extra_attrs.py_unit(py) } /// Is the :class:`.Operation` contained in this instruction a Qiskit standard gate? @@ -524,7 +614,7 @@ impl CircuitInstruction { pub struct OperationFromPython { pub operation: PackedOperation, pub params: SmallVec<[Param; 3]>, - pub extra_attrs: Option>, + pub extra_attrs: ExtraInstructionAttributes, } impl<'py> FromPyObject<'py> for OperationFromPython { @@ -558,8 +648,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython { ob.getattr(intern!(py, "duration"))?.extract()?, unit, ob.getattr(intern!(py, "condition"))?.extract()?, - ) - .map(Box::from)) + )) }; 'standard: { @@ -640,7 +729,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython { return Ok(OperationFromPython { operation: PackedOperation::from_operation(operation), params, - extra_attrs: None, + extra_attrs: ExtraInstructionAttributes::default(), }); } Err(PyTypeError::new_err(format!("invalid input: {}", ob))) diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 0e944789d307..5b218b2de818 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -2485,16 +2485,8 @@ def _format(operand): true }; let check_conditions = || -> PyResult { - if let Some(cond1) = inst1 - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - { - if let Some(cond2) = inst2 - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - { + if let Some(cond1) = inst1.extra_attrs.condition() { + if let Some(cond2) = inst2.extra_attrs.condition() { legacy_condition_eq .call1((cond1, cond2, &self_bit_indices, &other_bit_indices))? .extract::() @@ -2502,11 +2494,7 @@ def _format(operand): Ok(false) } } else { - Ok(inst2 - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - .is_none()) + Ok(inst2.extra_attrs.condition().is_none()) } }; @@ -3067,11 +3055,7 @@ def _format(operand): let node_map = if propagate_condition && !node.op.control_flow() { // Nested until https://github.com/rust-lang/rust/issues/53667 is fixed in a stable // release - if let Some(condition) = node - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - { + if let Some(condition) = node.extra_attrs.condition() { let mut in_dag = input_dag.copy_empty_like(py, "alike")?; // The remapping of `condition` below is still using the old code that assumes a 2-tuple. // This is because this remapping code only makes sense in the case of non-control-flow @@ -3164,12 +3148,7 @@ def _format(operand): for in_node_index in input_dag.topological_op_nodes()? { let in_node = &input_dag.dag[in_node_index]; if let NodeType::Operation(inst) = in_node { - if inst - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - .is_some() - { + if inst.extra_attrs.condition().is_some() { return Err(DAGCircuitError::new_err( "cannot propagate a condition to an element that already has one", )); @@ -3189,16 +3168,9 @@ def _format(operand): } let mut new_inst = inst.clone(); if new_condition.is_truthy()? { - if let Some(ref mut attrs) = new_inst.extra_attrs { - attrs.condition = Some(new_condition.as_any().clone().unbind()); - } else { - new_inst.extra_attrs = Some(Box::new(ExtraInstructionAttributes { - condition: Some(new_condition.as_any().clone().unbind()), - label: None, - duration: None, - unit: None, - })); - } + new_inst + .extra_attrs + .set_condition(Some(new_condition.as_any().clone().unbind())); #[cfg(feature = "cache_pygates")] { new_inst.py_op.take(); @@ -3283,13 +3255,7 @@ def _format(operand): let raw_target = old_op.instruction.getattr(py, "target")?; let target = raw_target.bind(py); let kwargs = PyDict::new_bound(py); - kwargs.set_item( - "label", - old_inst - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.label.as_ref()), - )?; + kwargs.set_item("label", old_inst.extra_attrs.label())?; let new_op = imports::SWITCH_CASE_OP.get_bound(py).call( ( variable_mapper.map_target(target)?, @@ -3318,11 +3284,7 @@ def _format(operand): } } } - if let Some(condition) = old_inst - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()) - { + if let Some(condition) = old_inst.extra_attrs.condition() { if old_inst.op.name() != "switch_case" { let new_condition: Option = variable_mapper .map_condition(condition.bind(py), false)? @@ -3332,18 +3294,7 @@ def _format(operand): if let NodeType::Operation(ref mut new_inst) = &mut self.dag[*new_node_index] { - match &mut new_inst.extra_attrs { - Some(attrs) => attrs.condition.clone_from(&new_condition), - None => { - new_inst.extra_attrs = - Some(Box::new(ExtraInstructionAttributes { - label: None, - condition: new_condition.clone(), - unit: None, - duration: None, - })) - } - } + new_inst.extra_attrs.set_condition(new_condition.clone()); #[cfg(feature = "cache_pygates")] { new_inst.py_op.take(); @@ -3440,14 +3391,8 @@ def _format(operand): .map(|x| Wire::Clbit(*x)), ) .collect(); - let (additional_clbits, additional_vars) = self.additional_wires( - py, - new_op.operation.view(), - new_op - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref()), - )?; + let (additional_clbits, additional_vars) = + self.additional_wires(py, new_op.operation.view(), new_op.extra_attrs.condition())?; new_wires.extend(additional_clbits.iter().map(|x| Wire::Clbit(*x))); new_wires.extend(additional_vars.iter().map(|x| Wire::Var(x.clone_ref(py)))); @@ -3470,12 +3415,7 @@ def _format(operand): && !(node.instruction.operation.control_flow() || new_op.operation.control_flow()) { // if new_op has a condition, the condition can't be propagated from the old node - if new_op - .extra_attrs - .as_ref() - .and_then(|extra| extra.condition.as_ref()) - .is_some() - { + if new_op.extra_attrs.condition().is_some() { return Err(DAGCircuitError::new_err( "Cannot propagate a condition to an operation that already has one.", )); @@ -3486,17 +3426,8 @@ def _format(operand): "Cannot add a condition on a generic Operation.", )); } - if let Some(ref mut extra) = extra_attrs { - extra.condition = Some(old_condition.clone_ref(py)); - } else { - extra_attrs = ExtraInstructionAttributes::new( - None, - None, - None, - Some(old_condition.clone_ref(py)), - ) - .map(Box::new) - } + extra_attrs.set_condition(Some(old_condition.clone_ref(py))); + let binding = self .control_flow_module .condition_resources(old_condition.bind(py))?; @@ -5029,11 +4960,9 @@ impl DAGCircuit { let filter_fn = move |node_index: NodeIndex| -> Result { let node = &self.dag[node_index]; match node { - NodeType::Operation(inst) => Ok(namelist.contains(inst.op.name()) - && match &inst.extra_attrs { - None => true, - Some(attrs) => attrs.condition.is_none(), - }), + NodeType::Operation(inst) => { + Ok(namelist.contains(inst.op.name()) && inst.extra_attrs.condition().is_none()) + } _ => Ok(false), } }; @@ -6276,7 +6205,7 @@ impl DAGCircuit { clbits: old_node.clbits, params: (!new_gate.1.is_empty()) .then(|| Box::new(new_gate.1.iter().map(|x| Param::Float(*x)).collect())), - extra_attrs: None, + extra_attrs: ExtraInstructionAttributes::default(), #[cfg(feature = "cache_pygates")] py_op: OnceCell::new(), } diff --git a/crates/circuit/src/dag_node.rs b/crates/circuit/src/dag_node.rs index ccae7a8c5d82..4d82cf31e813 100644 --- a/crates/circuit/src/dag_node.rs +++ b/crates/circuit/src/dag_node.rs @@ -368,34 +368,28 @@ impl DAGOpNode { #[getter] fn label(&self) -> Option<&str> { - self.instruction - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.label.as_deref()) + self.instruction.extra_attrs.label() } #[getter] fn condition(&self, py: Python) -> Option { self.instruction .extra_attrs - .as_ref() - .and_then(|attrs| attrs.condition.as_ref().map(|x| x.clone_ref(py))) + .condition() + .map(|x| x.clone_ref(py)) } #[getter] fn duration(&self, py: Python) -> Option { self.instruction .extra_attrs - .as_ref() - .and_then(|attrs| attrs.duration.as_ref().map(|x| x.clone_ref(py))) + .duration() + .map(|x| x.clone_ref(py)) } #[getter] fn unit(&self) -> Option<&str> { - self.instruction - .extra_attrs - .as_ref() - .and_then(|attrs| attrs.unit.as_deref()) + self.instruction.extra_attrs.unit() } /// Is the :class:`.Operation` contained in this node a Qiskit standard gate? @@ -426,30 +420,7 @@ impl DAGOpNode { #[setter] fn set_label(&mut self, val: Option) { - match self.instruction.extra_attrs.as_mut() { - Some(attrs) => attrs.label = val, - None => { - if val.is_some() { - self.instruction.extra_attrs = Some(Box::new( - crate::circuit_instruction::ExtraInstructionAttributes { - label: val, - duration: None, - unit: None, - condition: None, - }, - )) - } - } - }; - if let Some(attrs) = &self.instruction.extra_attrs { - if attrs.label.is_none() - && attrs.duration.is_none() - && attrs.unit.is_none() - && attrs.condition.is_none() - { - self.instruction.extra_attrs = None; - } - } + self.instruction.extra_attrs.set_label(val); } #[getter] diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index 2a341d687f6c..ad76e9d44008 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -425,22 +425,28 @@ impl StandardGate { &self, py: Python, params: Option<&[Param]>, - extra_attrs: Option<&ExtraInstructionAttributes>, + extra_attrs: &ExtraInstructionAttributes, ) -> PyResult> { let gate_class = get_std_gate_class(py, *self)?; let args = match params.unwrap_or(&[]) { &[] => PyTuple::empty_bound(py), params => PyTuple::new_bound(py, params), }; - if let Some(extra) = extra_attrs { + let (label, unit, duration, condition) = ( + extra_attrs.label(), + extra_attrs.unit(), + extra_attrs.duration(), + extra_attrs.condition(), + ); + if label.is_some() || unit.is_some() || duration.is_some() || condition.is_some() { let kwargs = [ - ("label", extra.label.to_object(py)), - ("unit", extra.py_unit(py).into_any()), - ("duration", extra.duration.to_object(py)), + ("label", label.to_object(py)), + ("unit", extra_attrs.py_unit(py).into_any()), + ("duration", duration.to_object(py)), ] .into_py_dict_bound(py); let mut out = gate_class.call_bound(py, args, Some(&kwargs))?; - if let Some(ref condition) = extra.condition { + if let Some(condition) = condition { out = out.call_method0(py, "to_mutable")?; out.setattr(py, "condition", condition)?; } diff --git a/crates/circuit/src/packed_instruction.rs b/crates/circuit/src/packed_instruction.rs index df8f9801314a..82c678031a15 100644 --- a/crates/circuit/src/packed_instruction.rs +++ b/crates/circuit/src/packed_instruction.rs @@ -497,7 +497,7 @@ pub struct PackedInstruction { /// The index under which the interner has stored `clbits`. pub clbits: Interned<[Clbit]>, pub params: Option>>, - pub extra_attrs: Option>, + pub extra_attrs: ExtraInstructionAttributes, #[cfg(feature = "cache_pygates")] /// This is hidden in a `OnceCell` because it's just an on-demand cache; we don't create this @@ -548,16 +548,12 @@ impl PackedInstruction { #[inline] pub fn condition(&self) -> Option<&Py> { - self.extra_attrs - .as_ref() - .and_then(|extra| extra.condition.as_ref()) + self.extra_attrs.condition() } #[inline] pub fn label(&self) -> Option<&str> { - self.extra_attrs - .as_ref() - .and_then(|extra| extra.label.as_deref()) + self.extra_attrs.label() } /// Build a reference to the Python-space operation object (the `Gate`, etc) packed into this @@ -573,7 +569,7 @@ impl PackedInstruction { OperationRef::Standard(standard) => standard.create_py_op( py, self.params.as_deref().map(SmallVec::as_slice), - self.extra_attrs.as_deref(), + &self.extra_attrs, ), OperationRef::Gate(gate) => Ok(gate.gate.clone_ref(py)), OperationRef::Instruction(instruction) => Ok(instruction.instruction.clone_ref(py)), From 653b5b66f5d856290acf26d40a9dac29ccfa21d5 Mon Sep 17 00:00:00 2001 From: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com> Date: Fri, 13 Sep 2024 17:35:03 +0300 Subject: [PATCH 81/85] Clean two_qubit_decompose code (#13093) * add pyfunction for decompose_two_qubit_product_gate * replace python code by rust for decompose_two_qubit_product_gate * remove unused code from two_qubit_decompose.py * updates following review comments * port trace_to_fid to rust * port Ud to rust * fix lint errors * fix lint errors * format * remove PyResult following review --- crates/accelerate/src/two_qubit_decompose.rs | 73 ++++++++++++++++++- .../two_qubit/two_qubit_decompose.py | 67 +---------------- test/python/synthesis/test_synthesis.py | 2 +- test/randomized/test_synthesis.py | 2 +- 4 files changed, 78 insertions(+), 66 deletions(-) diff --git a/crates/accelerate/src/two_qubit_decompose.rs b/crates/accelerate/src/two_qubit_decompose.rs index 92ad4724682f..76b92acd3faf 100644 --- a/crates/accelerate/src/two_qubit_decompose.rs +++ b/crates/accelerate/src/two_qubit_decompose.rs @@ -32,7 +32,7 @@ use ndarray::linalg::kron; use ndarray::prelude::*; use ndarray::Zip; use numpy::{IntoPyArray, ToPyArray}; -use numpy::{PyReadonlyArray1, PyReadonlyArray2}; +use numpy::{PyArray2, PyArrayLike2, PyReadonlyArray1, PyReadonlyArray2}; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; @@ -154,6 +154,15 @@ impl TraceToFidelity for c64 { } } +#[pyfunction] +#[pyo3(name = "trace_to_fid")] +/// Average gate fidelity is :math:`Fbar = (d + |Tr (Utarget \\cdot U^dag)|^2) / d(d+1)` +/// M. Horodecki, P. Horodecki and R. Horodecki, PRA 60, 1888 (1999) +fn py_trace_to_fid(trace: Complex64) -> PyResult { + let fid = trace.trace_to_fid(); + Ok(fid) +} + fn decompose_two_qubit_product_gate( special_unitary: ArrayView2, ) -> PyResult<(Array2, Array2, f64)> { @@ -182,9 +191,31 @@ fn decompose_two_qubit_product_gate( } l.mapv_inplace(|x| x / det_l.sqrt()); let phase = det_l.arg() / 2.; + Ok((l, r, phase)) } +#[pyfunction] +#[pyo3(name = "decompose_two_qubit_product_gate")] +/// Decompose :math:`U = U_l \otimes U_r` where :math:`U \in SU(4)`, +/// and :math:`U_l,~U_r \in SU(2)`. +/// Args: +/// special_unitary_matrix: special unitary matrix to decompose +/// Raises: +/// QiskitError: if decomposition isn't possible. +fn py_decompose_two_qubit_product_gate( + py: Python, + special_unitary: PyArrayLike2, +) -> PyResult<(PyObject, PyObject, f64)> { + let view = special_unitary.as_array(); + let (l, r, phase) = decompose_two_qubit_product_gate(view)?; + Ok(( + l.into_pyarray_bound(py).unbind().into(), + r.into_pyarray_bound(py).unbind().into(), + phase, + )) +} + fn __weyl_coordinates(unitary: MatRef) -> [f64; 3] { let uscaled = scale(C1 / unitary.determinant().powf(0.25)) * unitary; let uup = transform_from_magic_basis(uscaled); @@ -301,6 +332,43 @@ fn rz_matrix(theta: f64) -> Array2 { array![[(-ilam2).exp(), C_ZERO], [C_ZERO, ilam2.exp()]] } +/// Generates the array :math:`e^{(i a XX + i b YY + i c ZZ)}` +fn ud(a: f64, b: f64, c: f64) -> Array2 { + array![ + [ + (IM * c).exp() * (a - b).cos(), + C_ZERO, + C_ZERO, + IM * (IM * c).exp() * (a - b).sin() + ], + [ + C_ZERO, + (M_IM * c).exp() * (a + b).cos(), + IM * (M_IM * c).exp() * (a + b).sin(), + C_ZERO + ], + [ + C_ZERO, + IM * (M_IM * c).exp() * (a + b).sin(), + (M_IM * c).exp() * (a + b).cos(), + C_ZERO + ], + [ + IM * (IM * c).exp() * (a - b).sin(), + C_ZERO, + C_ZERO, + (IM * c).exp() * (a - b).cos() + ] + ] +} + +#[pyfunction] +#[pyo3(name = "Ud")] +fn py_ud(py: Python, a: f64, b: f64, c: f64) -> Py> { + let ud_mat = ud(a, b, c); + ud_mat.into_pyarray_bound(py).unbind() +} + fn compute_unitary(sequence: &TwoQubitSequenceVec, global_phase: f64) -> Array2 { let identity = aview2(&ONE_QUBIT_IDENTITY); let phase = c64(0., global_phase).exp(); @@ -2278,9 +2346,12 @@ pub fn local_equivalence(weyl: PyReadonlyArray1) -> PyResult<[f64; 3]> { pub fn two_qubit_decompose(m: &Bound) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(_num_basis_gates))?; + m.add_wrapped(wrap_pyfunction!(py_decompose_two_qubit_product_gate))?; m.add_wrapped(wrap_pyfunction!(two_qubit_decompose_up_to_diagonal))?; m.add_wrapped(wrap_pyfunction!(two_qubit_local_invariants))?; m.add_wrapped(wrap_pyfunction!(local_equivalence))?; + m.add_wrapped(wrap_pyfunction!(py_trace_to_fid))?; + m.add_wrapped(wrap_pyfunction!(py_ud))?; m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/qiskit/synthesis/two_qubit/two_qubit_decompose.py b/qiskit/synthesis/two_qubit/two_qubit_decompose.py index 0e3427773387..d4c7702da35a 100644 --- a/qiskit/synthesis/two_qubit/two_qubit_decompose.py +++ b/qiskit/synthesis/two_qubit/two_qubit_decompose.py @@ -24,8 +24,6 @@ arXiv:1811.12926 [quant-ph] (2018). """ from __future__ import annotations -import cmath -import math import io import base64 import warnings @@ -91,41 +89,18 @@ def decompose_two_qubit_product_gate(special_unitary_matrix: np.ndarray): QiskitError: if decomposition isn't possible. """ special_unitary_matrix = np.asarray(special_unitary_matrix, dtype=complex) - # extract the right component - R = special_unitary_matrix[:2, :2].copy() - detR = R[0, 0] * R[1, 1] - R[0, 1] * R[1, 0] - if abs(detR) < 0.1: - R = special_unitary_matrix[2:, :2].copy() - detR = R[0, 0] * R[1, 1] - R[0, 1] * R[1, 0] - if abs(detR) < 0.1: - raise QiskitError("decompose_two_qubit_product_gate: unable to decompose: detR < 0.1") - R /= np.sqrt(detR) - - # extract the left component - temp = np.kron(np.eye(2), R.T.conj()) - temp = special_unitary_matrix.dot(temp) - L = temp[::2, ::2] - detL = L[0, 0] * L[1, 1] - L[0, 1] * L[1, 0] - if abs(detL) < 0.9: - raise QiskitError("decompose_two_qubit_product_gate: unable to decompose: detL < 0.9") - L /= np.sqrt(detL) - phase = cmath.phase(detL) / 2 + (L, R, phase) = two_qubit_decompose.decompose_two_qubit_product_gate(special_unitary_matrix) temp = np.kron(L, R) deviation = abs(abs(temp.conj().T.dot(special_unitary_matrix).trace()) - 4) + if deviation > 1.0e-13: raise QiskitError( "decompose_two_qubit_product_gate: decomposition failed: " f"deviation too large: {deviation}" ) - return L, R, phase - - -_ipx = np.array([[0, 1j], [1j, 0]], dtype=complex) -_ipy = np.array([[0, 1], [-1, 0]], dtype=complex) -_ipz = np.array([[1j, 0], [0, -1j]], dtype=complex) -_id = np.array([[1, 0], [0, 1]], dtype=complex) + return (L, R, phase) class TwoQubitWeylDecomposition: @@ -239,7 +214,7 @@ def actual_fidelity(self, **kwargs) -> float: """Calculates the actual fidelity of the decomposed circuit to the input unitary.""" circ = self.circuit(**kwargs) trace = np.trace(Operator(circ).data.T.conj() @ self.unitary_matrix) - return trace_to_fid(trace) + return two_qubit_decompose.trace_to_fid(trace) def __repr__(self): """Represent with enough precision to allow copy-paste debugging of all corner cases""" @@ -460,40 +435,6 @@ def _weyl_gate(self, circ: QuantumCircuit, atol=1.0e-13): return circ -def Ud(a, b, c): - r"""Generates the array :math:`e^{(i a XX + i b YY + i c ZZ)}`""" - return np.array( - [ - [cmath.exp(1j * c) * math.cos(a - b), 0, 0, 1j * cmath.exp(1j * c) * math.sin(a - b)], - [0, cmath.exp(-1j * c) * math.cos(a + b), 1j * cmath.exp(-1j * c) * math.sin(a + b), 0], - [0, 1j * cmath.exp(-1j * c) * math.sin(a + b), cmath.exp(-1j * c) * math.cos(a + b), 0], - [1j * cmath.exp(1j * c) * math.sin(a - b), 0, 0, cmath.exp(1j * c) * math.cos(a - b)], - ], - dtype=complex, - ) - - -def trace_to_fid(trace): - r"""Average gate fidelity is - - .. math:: - - \bar{F} = \frac{d + |\mathrm{Tr} (U_\text{target} \cdot U^{\dag})|^2}{d(d+1)} - - M. Horodecki, P. Horodecki and R. Horodecki, PRA 60, 1888 (1999)""" - return (4 + abs(trace) ** 2) / 20 - - -def rz_array(theta): - """Return numpy array for Rz(theta). - - Rz(theta) = diag(exp(-i*theta/2),exp(i*theta/2)) - """ - return np.array( - [[cmath.exp(-1j * theta / 2.0), 0], [0, cmath.exp(1j * theta / 2.0)]], dtype=complex - ) - - class TwoQubitBasisDecomposer: """A class for decomposing 2-qubit unitaries into minimal number of uses of a 2-qubit basis gate. diff --git a/test/python/synthesis/test_synthesis.py b/test/python/synthesis/test_synthesis.py index b4fac3f427f0..b08240197211 100644 --- a/test/python/synthesis/test_synthesis.py +++ b/test/python/synthesis/test_synthesis.py @@ -59,11 +59,11 @@ two_qubit_cnot_decompose, TwoQubitBasisDecomposer, TwoQubitControlledUDecomposer, - Ud, decompose_two_qubit_product_gate, ) from qiskit._accelerate.two_qubit_decompose import two_qubit_decompose_up_to_diagonal from qiskit._accelerate.two_qubit_decompose import Specialization +from qiskit._accelerate.two_qubit_decompose import Ud from qiskit.synthesis.unitary import qsd from test import combine # pylint: disable=wrong-import-order from test import QiskitTestCase # pylint: disable=wrong-import-order diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index 9f0619a0c296..5e500b78dafc 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -23,8 +23,8 @@ from qiskit.synthesis.two_qubit.two_qubit_decompose import ( two_qubit_cnot_decompose, TwoQubitBasisDecomposer, - Ud, ) +from qiskit._accelerate.two_qubit_decompose import Ud class TestSynthesis(CheckDecompositions): From a0918b8fc6c25bd9cb35ede1b7778f7ae9178aed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:59:12 +0100 Subject: [PATCH 82/85] Bump once_cell from 1.19.0 to 1.20.0 (#13156) Bumps [once_cell](https://github.com/matklad/once_cell) from 1.19.0 to 1.20.0. - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.19.0...v1.20.0) --- updated-dependencies: - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/accelerate/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d73b21266dab..15f5a7833ca5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,9 +903,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "oq3_lexer" diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index 4b5c18e5eb93..4c570f4a5285 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -25,7 +25,7 @@ itertools.workspace = true qiskit-circuit.workspace = true thiserror.workspace = true ndarray_einsum_beta = "0.7" -once_cell = "1.19.0" +once_cell = "1.20.0" [dependencies.smallvec] workspace = true From 87836411a897a977b3d19c4a76d71634c47d7747 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 16 Sep 2024 16:59:21 -0400 Subject: [PATCH 83/85] Add LightSABRE citation to sabre documentation (#13160) * Add LightSABRE citation to sabre documentation We recently published a pre-print of a new paper that describes all the improvements we've developed ontop of the original SABRE algorithm as part of Qiskit's implementation. This commit adds a citation for that new paper to the documentation of the two sabre passes in qiskit to better document how the pass works in practice. * Add missing citation to SabrePreLayout and fix formatting in SabreSwap * Tweak wording in sabre swap docstring --- qiskit/transpiler/passes/layout/sabre_layout.py | 5 ++++- qiskit/transpiler/passes/layout/sabre_pre_layout.py | 5 +++++ qiskit/transpiler/passes/routing/sabre_swap.py | 10 +++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/qiskit/transpiler/passes/layout/sabre_layout.py b/qiskit/transpiler/passes/layout/sabre_layout.py index 7e7031ec3361..78af67ad9118 100644 --- a/qiskit/transpiler/passes/layout/sabre_layout.py +++ b/qiskit/transpiler/passes/layout/sabre_layout.py @@ -101,7 +101,10 @@ class SabreLayout(TransformationPass): **References:** - [1] Li, Gushu, Yufei Ding, and Yuan Xie. "Tackling the qubit mapping problem + [1] Henry Zou and Matthew Treinish and Kevin Hartman and Alexander Ivrii and Jake Lishman. + "LightSABRE: A Lightweight and Enhanced SABRE Algorithm" + `arXiv:2409.08368 `__ + [2] Li, Gushu, Yufei Ding, and Yuan Xie. "Tackling the qubit mapping problem for NISQ-era quantum devices." ASPLOS 2019. `arXiv:1809.02573 `_ """ diff --git a/qiskit/transpiler/passes/layout/sabre_pre_layout.py b/qiskit/transpiler/passes/layout/sabre_pre_layout.py index 4a7ea35e3f2a..1fd4f60e254f 100644 --- a/qiskit/transpiler/passes/layout/sabre_pre_layout.py +++ b/qiskit/transpiler/passes/layout/sabre_pre_layout.py @@ -31,6 +31,11 @@ class SabrePreLayout(AnalysisPass): ``sabre_starting_layouts`` (``list[Layout]``) An optional list of :class:`~.Layout` objects to use for additional Sabre layout trials. + **References:** + + [1] Henry Zou and Matthew Treinish and Kevin Hartman and Alexander Ivrii and Jake Lishman. + "LightSABRE: A Lightweight and Enhanced SABRE Algorithm" + `arXiv:2409.08368 `__ """ def __init__( diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index 9edd1ceee445..238444067168 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -41,8 +41,9 @@ class SabreSwap(TransformationPass): r"""Map input circuit onto a backend topology via insertion of SWAPs. Implementation of the SWAP-based heuristic search from the SABRE qubit - mapping paper [1] (Algorithm 1). The heuristic aims to minimize the number - of lossy SWAPs inserted and the depth of the circuit. + mapping paper [2] (Algorithm 1) with the modifications from the LightSABRE + paper [1]. The heuristic aims to minimize the number of lossy SWAPs inserted + and the depth of the circuit. This algorithm starts from an initial layout of virtual qubits onto physical qubits, and iterates over the circuit DAG until all gates are exhausted, @@ -69,7 +70,10 @@ class SabreSwap(TransformationPass): **References:** - [1] Li, Gushu, Yufei Ding, and Yuan Xie. "Tackling the qubit mapping problem + [1] Henry Zou and Matthew Treinish and Kevin Hartman and Alexander Ivrii and Jake Lishman. + "LightSABRE: A Lightweight and Enhanced SABRE Algorithm" + `arXiv:2409.08368 `__ + [2] Li, Gushu, Yufei Ding, and Yuan Xie. "Tackling the qubit mapping problem for NISQ-era quantum devices." ASPLOS 2019. `arXiv:1809.02573 `_ """ From c68e80329cafbf00639e85c92e2d455462be0b2c Mon Sep 17 00:00:00 2001 From: Raynel Sanchez <87539502+raynelfss@users.noreply.github.com> Date: Tue, 17 Sep 2024 17:55:21 -0400 Subject: [PATCH 84/85] Add rust-native `apply_operation` methods (#13143) * Initial: Add rust-native `apply_operation_front` and `apply_operation_back methods. - These methods allow rust users to add an operation to either the front or the back of the circuit without needing to have valid interned indices for the Qargs/Qargs of said operations. - Leverage the new methods in the existing python variants of them. * Fix: Remove extra blank space * Fix: Revert changes to python `apply_op` methods. - To avoid an ownership issue, usage of the new methods from the Python variants has been removed. - As requested, the insertion check in the rust `apply_op` has been removed. * Fix: Adapt to new `ExtraInstructionProperties` infrastructure. * Format: Change redundant iteration statement for params --- crates/circuit/src/dag_circuit.rs | 111 +++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 5b218b2de818..54f270b30558 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -13,6 +13,7 @@ use std::hash::{Hash, Hasher}; use ahash::RandomState; +use smallvec::SmallVec; use crate::bit_data::BitData; use crate::circuit_data::CircuitData; @@ -26,7 +27,7 @@ use crate::error::DAGCircuitError; use crate::imports; use crate::interner::{Interned, Interner}; use crate::operations::{Operation, OperationRef, Param, PyInstruction, StandardGate}; -use crate::packed_instruction::PackedInstruction; +use crate::packed_instruction::{PackedInstruction, PackedOperation}; use crate::rustworkx_core_vnext::isomorphism; use crate::{BitType, Clbit, Qubit, TupleLikeArg}; @@ -5192,6 +5193,114 @@ impl DAGCircuit { Ok(new_node) } + /// Apply a [PackedOperation] to the back of the circuit. + pub fn apply_operation_back( + &mut self, + py: Python, + op: PackedOperation, + qargs: &[Qubit], + cargs: &[Clbit], + params: Option>, + extra_attrs: ExtraInstructionAttributes, + #[cfg(feature = "cache_pygates")] py_op: Option, + ) -> PyResult { + self.inner_apply_op( + py, + op, + qargs, + cargs, + params, + extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op, + false, + ) + } + + /// Apply a [PackedOperation] to the front of the circuit. + pub fn apply_operation_front( + &mut self, + py: Python, + op: PackedOperation, + qargs: &[Qubit], + cargs: &[Clbit], + params: Option>, + extra_attrs: ExtraInstructionAttributes, + #[cfg(feature = "cache_pygates")] py_op: Option, + ) -> PyResult { + self.inner_apply_op( + py, + op, + qargs, + cargs, + params, + extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op, + true, + ) + } + + #[inline] + #[allow(clippy::too_many_arguments)] + fn inner_apply_op( + &mut self, + py: Python, + op: PackedOperation, + qargs: &[Qubit], + cargs: &[Clbit], + params: Option>, + extra_attrs: ExtraInstructionAttributes, + #[cfg(feature = "cache_pygates")] py_op: Option, + front: bool, + ) -> PyResult { + // Check that all qargs are within an acceptable range + qargs.iter().try_for_each(|qarg| { + if qarg.0 as usize >= self.num_qubits() { + return Err(PyValueError::new_err(format!( + "Qubit index {} is out of range. This DAGCircuit currently has only {} qubits.", + qarg.0, + self.num_qubits() + ))); + } + Ok(()) + })?; + + // Check that all cargs are within an acceptable range + cargs.iter().try_for_each(|carg| { + if carg.0 as usize >= self.num_clbits() { + return Err(PyValueError::new_err(format!( + "Clbit index {} is out of range. This DAGCircuit currently has only {} clbits.", + carg.0, + self.num_clbits() + ))); + } + Ok(()) + })?; + + #[cfg(feature = "cache_pygates")] + let py_op = if let Some(py_op) = py_op { + py_op.into() + } else { + OnceCell::new() + }; + let packed_instruction = PackedInstruction { + op, + qubits: self.qargs_interner.insert(qargs), + clbits: self.cargs_interner.insert(cargs), + params: params.map(Box::new), + extra_attrs, + #[cfg(feature = "cache_pygates")] + py_op, + }; + + if front { + self.push_front(py, packed_instruction) + } else { + self.push_back(py, packed_instruction) + } + } + fn sort_key(&self, node: NodeIndex) -> SortKeyType { match &self.dag[node] { NodeType::Operation(packed) => ( From f091cf291a0a478cf808d90287a45c8a1b786134 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Wed, 18 Sep 2024 08:33:56 +0100 Subject: [PATCH 85/85] Add example of `qasm2.CustomInstruction` (#13167) We didn't have an explicit usage example of this in the documentation before, and several people seem to have been confused by it. --- qiskit/qasm2/parse.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/qiskit/qasm2/parse.py b/qiskit/qasm2/parse.py index a40270a99b8c..6cdb0f70bba0 100644 --- a/qiskit/qasm2/parse.py +++ b/qiskit/qasm2/parse.py @@ -89,6 +89,35 @@ class CustomInstruction: There is a final ``builtin`` field. This is optional, and if set true will cause the instruction to be defined and available within the parsing, even if there is no definition in any included OpenQASM 2 file. + + Examples: + + Instruct the importer to use Qiskit's :class:`.ECRGate` and :class:`.RZXGate` objects to + interpret ``gate`` statements that are known to have been created from those same objects + during OpenQASM 2 export:: + + from qiskit import qasm2 + from qiskit.circuit import QuantumCircuit, library + + qc = QuantumCircuit(2) + qc.ecr(0, 1) + qc.rzx(0.3, 0, 1) + qc.rzx(0.7, 1, 0) + qc.rzx(1.5, 0, 1) + qc.ecr(1, 0) + + # This output string includes `gate ecr q0, q1 { ... }` and `gate rzx(p) q0, q1 { ... }` + # statements, since `ecr` and `rzx` are neither built-in gates nor in ``qelib1.inc``. + dumped = qasm2.dumps(qc) + + # Tell the importer how to interpret the `gate` statements, which we know are safe + # because we controlled the input OpenQASM 2 source. + custom = [ + qasm2.CustomInstruction("ecr", 0, 2, library.ECRGate), + qasm2.CustomInstruction("rzx", 1, 2, library.RZXGate), + ] + + loaded = qasm2.loads(dumped, custom_instructions=custom) """ name: str

    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