diff --git a/_metadata.py b/_metadata.py index e2fc2daa..da4d1a4e 100644 --- a/_metadata.py +++ b/_metadata.py @@ -1,2 +1,2 @@ -__extension_version__ = "0.38.0" +__extension_version__ = "0.39.0" __extension_name__ = "pytket-qiskit" diff --git a/docs/changelog.rst b/docs/changelog.rst index 4b328381..386bfb96 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ~~~~~~~~~ +0.39.0 (May 2023) +----------------- + +* Updated pytket version requirement to 1.15. +* The get_compiled_circuit method now allows for optional arguments to override the default settings in the NoiseAwarePlacement + 0.38.0 (April 2023) ------------------- diff --git a/docs/intro.txt b/docs/intro.txt index 33701ff2..b742ac14 100644 --- a/docs/intro.txt +++ b/docs/intro.txt @@ -114,7 +114,7 @@ and several types of simulator. * - `AerUnitaryBackend `_ - Unitary simulator -* [1] :py:class`AerBackend` is noiseless by default and has no architecture. However it can accept a user defined :py:class:`NoiseModel` and :py:class:`Architecture`. +* [1] :py:class:`AerBackend` is noiseless by default and has no architecture. However it can accept a user defined :py:class:`NoiseModel` and :py:class:`Architecture`. * In addition to the backends above the ``pytket-qiskit`` extension also has the :py:class:`TketBackend`. This allows a tket :py:class:`Backend` to be used directly through qiskit. see the `notebook example `_ on qiskit integration. Default Compilation diff --git a/pytket/extensions/qiskit/backends/aer.py b/pytket/extensions/qiskit/backends/aer.py index 0a495101..cf0bb441 100644 --- a/pytket/extensions/qiskit/backends/aer.py +++ b/pytket/extensions/qiskit/backends/aer.py @@ -127,18 +127,32 @@ def rebase_pass(self) -> BasePass: ) def _arch_dependent_default_compilation_pass( - self, arch: Architecture, optimisation_level: int = 2 + self, + arch: Architecture, + optimisation_level: int = 2, + placement_options: Optional[Dict] = None, ) -> BasePass: assert optimisation_level in range(3) + if placement_options is not None: + noise_aware_placement = NoiseAwarePlacement( + arch, + self._backend_info.averaged_node_gate_errors, + self._backend_info.averaged_edge_gate_errors, + self._backend_info.averaged_readout_errors, + **placement_options, + ) + else: + noise_aware_placement = NoiseAwarePlacement( + arch, + self._backend_info.averaged_node_gate_errors, + self._backend_info.averaged_edge_gate_errors, + self._backend_info.averaged_readout_errors, + ) + arch_specific_passes = [ CXMappingPass( arch, - NoiseAwarePlacement( - arch, - self._backend_info.averaged_node_gate_errors, - self._backend_info.averaged_edge_gate_errors, - self._backend_info.averaged_readout_errors, - ), + noise_aware_placement, directed_cx=True, delay_measures=False, ), @@ -182,11 +196,16 @@ def _arch_independent_default_compilation_pass( return SequencePass([DecomposeBoxes(), SynthesiseTket()]) return SequencePass([DecomposeBoxes(), FullPeepholeOptimise()]) - def default_compilation_pass(self, optimisation_level: int = 2) -> BasePass: + def default_compilation_pass( + self, optimisation_level: int = 2, placement_options: Optional[Dict] = None + ) -> BasePass: + """ + See documentation for :py:meth:`IBMQBackend.default_compilation_pass`. + """ arch = self._backend_info.architecture if arch.coupling and self._backend_info.get_misc("characterisation"): return self._arch_dependent_default_compilation_pass( - arch, optimisation_level + arch, optimisation_level, placement_options=placement_options ) return self._arch_independent_default_compilation_pass(optimisation_level) diff --git a/pytket/extensions/qiskit/backends/ibm.py b/pytket/extensions/qiskit/backends/ibm.py index 472ebf50..ba1ec0b4 100644 --- a/pytket/extensions/qiskit/backends/ibm.py +++ b/pytket/extensions/qiskit/backends/ibm.py @@ -346,7 +346,42 @@ def required_predicates(self) -> List[Predicate]: ] + predicates return predicates - def default_compilation_pass(self, optimisation_level: int = 2) -> BasePass: + def default_compilation_pass( + self, optimisation_level: int = 2, placement_options: Optional[Dict] = None + ) -> BasePass: + """ + A suggested compilation pass that will will, if possible, produce an equivalent + circuit suitable for running on this backend. + + At a minimum it will ensure that compatible gates are used and that all two- + qubit interactions are compatible with the backend's qubit architecture. At + higher optimisation levels, further optimisations may be applied. + + This is a an abstract method which is implemented in the backend itself, and so + is tailored to the backend's requirements. + + The default compilation passes for the :py:class:`IBMQBackend`, + :py:class:`IBMQEmulatorBackend` and the + Aer simulators support an optional ``placement_options`` dictionary containing + arguments to override the default settings in :py:class:`NoiseAwarePlacement`. + + :param optimisation_level: The level of optimisation to perform during + compilation. + + - Level 0 does the minimum required to solves the device constraints, + without any optimisation. + - Level 1 additionally performs some light optimisations. + - Level 2 (the default) adds more computationally intensive optimisations + that should give the best results from execution. + + :type optimisation_level: int, optional + + :param placement_options: Optional argument allowing the user to override + the default settings in :py:class:`NoiseAwarePlacement`. + :type placement_options: Dict, optional + :return: Compilation pass guaranteeing required predicates. + :rtype: BasePass + """ assert optimisation_level in range(3) passlist = [DecomposeBoxes()] # If you make changes to the default_compilation_pass, @@ -363,15 +398,26 @@ def default_compilation_pass(self, optimisation_level: int = 2) -> BasePass: mid_measure = self._backend_info.supports_midcircuit_measurement arch = self._backend_info.architecture if not isinstance(arch, FullyConnected): + if placement_options is not None: + noise_aware_placement = NoiseAwarePlacement( + arch, + self._backend_info.averaged_node_gate_errors, + self._backend_info.averaged_edge_gate_errors, + self._backend_info.averaged_readout_errors, + **placement_options, + ) + else: + noise_aware_placement = NoiseAwarePlacement( + arch, + self._backend_info.averaged_node_gate_errors, + self._backend_info.averaged_edge_gate_errors, + self._backend_info.averaged_readout_errors, + ) + passlist.append( CXMappingPass( arch, - NoiseAwarePlacement( - arch, - self._backend_info.averaged_node_gate_errors, - self._backend_info.averaged_edge_gate_errors, - self._backend_info.averaged_readout_errors, - ), + noise_aware_placement, directed_cx=False, delay_measures=(not mid_measure), ) diff --git a/pytket/extensions/qiskit/backends/ibmq_emulator.py b/pytket/extensions/qiskit/backends/ibmq_emulator.py index e3d1549e..9c1c5aa6 100644 --- a/pytket/extensions/qiskit/backends/ibmq_emulator.py +++ b/pytket/extensions/qiskit/backends/ibmq_emulator.py @@ -108,9 +108,14 @@ def backend_info(self) -> BackendInfo: def required_predicates(self) -> List[Predicate]: return self._ibmq.required_predicates - def default_compilation_pass(self, optimisation_level: int = 2) -> BasePass: + def default_compilation_pass( + self, optimisation_level: int = 2, placement_options: Optional[Dict] = None + ) -> BasePass: + """ + See documentation for :py:meth:`IBMQBackend.default_compilation_pass`. + """ return self._ibmq.default_compilation_pass( - optimisation_level=optimisation_level + optimisation_level=optimisation_level, placement_options=placement_options ) @property diff --git a/setup.py b/setup.py index 36d6c0aa..da2cdfb0 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ packages=find_namespace_packages(include=["pytket.*"]), include_package_data=True, install_requires=[ - "pytket ~= 1.14", + "pytket ~= 1.15", "qiskit ~= 0.42.1", "qiskit-ibm-runtime ~= 0.9.2", "qiskit-aer ~= 0.12.0",