Skip to content

Commit

Permalink
Merge pull request #189 from CQCL/release/1.21.0
Browse files Browse the repository at this point in the history
Release/1.21.0
  • Loading branch information
cqc-melf authored Oct 17, 2023
2 parents ee1e3b3 + bde1382 commit 4e5a073
Show file tree
Hide file tree
Showing 25 changed files with 803 additions and 199 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,17 @@ jobs:
with:
python-version: '3.10'
- name: Build and test including remote checks (3.10) mypy
if: (matrix.os == 'macos-12') && (github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'release' || github.event_name == 'schedule' )
if: (matrix.os == 'ubuntu-22.04') && (github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'release' || github.event_name == 'schedule' )
shell: bash
run: |
./.github/workflows/build-test mypy
env:
PYTKET_RUN_REMOTE_TESTS: 1
- name: Build and test including remote checks (3.10) nomypy
- name: Build and test (3.10) nomypy
if: (matrix.os != 'macos-12') && (github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'release' || github.event_name == 'schedule')
shell: bash
run: |
./.github/workflows/build-test nomypy
env:
PYTKET_RUN_REMOTE_TESTS: 1
- name: Set up Python 3.11
if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'schedule'
uses: actions/setup-python@v4
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ def correct_signature(
signature: str,
return_annotation: str,
) -> (str, str):

new_signature = signature
new_return_annotation = return_annotation
for k, v in app.config.custom_internal_mapping.items():
Expand Down
2 changes: 1 addition & 1 deletion _metadata.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__extension_version__ = "0.44.0"
__extension_version__ = "0.45.0"
__extension_name__ = "pytket-qiskit"
8 changes: 8 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Changelog
~~~~~~~~~

0.45.0 (October 2023)
---------------------

* Updated pytket version requirement to 1.21.
* Implement crosstalk noise model for AerBackend.
* Don't include ``SimplifyInitial`` in default passes; instead make it an option
to ``process_circuits()``.

0.44.0 (September 2023)
-----------------------

Expand Down
12 changes: 4 additions & 8 deletions docs/intro.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,28 +164,24 @@ Every :py:class:`Backend` in pytket has its own ``default_compilation_pass`` met
- `SynthesiseTket <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.SynthesiseTket>`_
- `KAKDecomposition(allow_swaps=False) <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.KAKDecomposition>`_
* - `RemoveRedundancies <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.RemoveRedundancies>`_
- `RemoveRedundancies <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.RemoveRedundancies>`_
- self.rebase_pass [2]
- `CliffordSimp(allow_swaps=False) <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.CliffordSimp>`_
* -
- self.rebase_pass [2]
- `RemoveRedundancies <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.RemoveRedundancies>`_
- `SynthesiseTket <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.SynthesiseTket>`_
* -
- `SimplifyInitial <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.SimplifyInitial>`_ [4]
-
- self.rebase_pass [2]
* -
-
- `RemoveRedundancies <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.RemoveRedundancies>`_
* -
-
- `SimplifyInitial <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.SimplifyInitial>`_ [4]

* [1] If no value is specified then ``optimisation_level`` defaults to a value of 2.
* [2] self.rebase_pass is a rebase to the gateset supported by the backend, For IBM quantum devices that is {X, SX, Rz, CX}.
* [3] Here :py:class:`CXMappingPass` maps program qubits to the architecture using a `NoiseAwarePlacement <https://cqcl.github.io/tket/pytket/api/placement.html#pytket.placement.NoiseAwarePlacement>`_
* [4] :py:class:`SimplifyInitial` has arguments ``allow_classical=False`` and ``create_all_qubits=True``.


**Note:** The ``default_compilation_pass`` for :py:class:`AerBackend` is the same as above except it doesn't use :py:class:`SimplifyInitial`.
**Note:** The ``default_compilation_pass`` for :py:class:`AerBackend` is the same as above.


Backend Predicates
Expand Down
12 changes: 12 additions & 0 deletions ecosystem.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"dependencies_files": [
"tests/test-requirements.txt"
],
"language": {
"name": "python",
"versions": ["3.9"]
},
"tests_command": [
"/bin/bash -ec 'cd tests && pytest'"
]
}
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace_packages = True
check_untyped_defs = True

warn_redundant_casts = True
warn_unused_ignores = False
warn_unused_ignores = True
warn_no_return = False
warn_return_any = True
warn_unreachable = True
Expand Down
2 changes: 1 addition & 1 deletion pytket/extensions/qiskit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""Module for conversion between IBM Qiskit and tket primitives."""

# _metadata.py is copied to the folder after installation.
from ._metadata import __extension_version__, __extension_name__ # type: ignore
from ._metadata import __extension_version__, __extension_name__
from .backends import (
IBMQBackend,
NoIBMQCredentialsError,
Expand Down
109 changes: 77 additions & 32 deletions pytket/extensions/qiskit/backends/aer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,19 @@
)

import numpy as np
from qiskit import transpile # type: ignore
from qiskit.providers.aer.noise import NoiseModel # type: ignore
from qiskit.quantum_info.operators import Pauli as qk_Pauli # type: ignore
from qiskit.quantum_info.operators.symplectic.sparse_pauli_op import SparsePauliOp # type: ignore
from qiskit_aer import Aer # type: ignore
from qiskit_aer.library import save_expectation_value # type: ignore # pylint: disable=unused-import
from pytket.architecture import Architecture, FullyConnected # type: ignore
from pytket.architecture import Architecture, FullyConnected
from pytket.backends import Backend, CircuitNotRunError, CircuitStatus, ResultHandle
from pytket.backends.backendinfo import BackendInfo
from pytket.backends.backendresult import BackendResult
from pytket.backends.resulthandle import _ResultIdTuple
from pytket.circuit import Circuit, Node, OpType, Qubit # type: ignore
from pytket.passes import ( # type: ignore
from pytket.circuit import Circuit, Node, OpType, Qubit
from pytket.passes import (
BasePass,
CliffordSimp,
CXMappingPass,
Expand All @@ -51,14 +52,16 @@
auto_rebase_pass,
NaivePlacementPass,
)
from pytket.pauli import Pauli, QubitPauliString # type: ignore
from pytket.placement import NoiseAwarePlacement # type: ignore
from pytket.predicates import ( # type: ignore
from pytket.pauli import Pauli, QubitPauliString
from pytket.placement import NoiseAwarePlacement
from pytket.predicates import (
ConnectivityPredicate,
GateSetPredicate,
NoClassicalControlPredicate,
NoBarriersPredicate,
NoFastFeedforwardPredicate,
NoSymbolsPredicate,
DefaultRegisterPredicate,
Predicate,
)
from pytket.utils.operators import QubitPauliOperator
Expand All @@ -71,6 +74,10 @@
_gate_str_2_optype,
)
from ..result_convert import qiskit_result_to_backendresult
from .crosstalk_model import (
NoisyCircuitBuilder,
CrosstalkParams,
)

if TYPE_CHECKING:
from qiskit.providers.aer import AerJob # type: ignore
Expand Down Expand Up @@ -116,6 +123,7 @@ class _AerBaseBackend(Backend):
_required_predicates: List[Predicate]
_noise_model: Optional[NoiseModel] = None
_has_arch: bool = False
_needs_transpile: bool = False

@property
def required_predicates(self) -> List[Predicate]:
Expand Down Expand Up @@ -239,6 +247,14 @@ def process_circuits(
if valid_check:
self._check_all_circuits(circuits)

if hasattr(self, "_crosstalk_params") and self._crosstalk_params is not None:
noisy_circuits = []
for c in circuits:
noisy_circ_builder = NoisyCircuitBuilder(c, self._crosstalk_params)
noisy_circ_builder.build()
noisy_circuits.append(noisy_circ_builder.get_circuit())
circuits = noisy_circuits

handle_list: List[Optional[ResultHandle]] = [None] * len(circuits)
circuit_batches, batch_order = _batch_circuits(circuits, n_shots_list)

Expand All @@ -254,6 +270,9 @@ def process_circuits(
qc.save_unitary()
qcs.append(qc)

if self._needs_transpile:
qcs = transpile(qcs, self._qiskit_backend)

seed = cast(Optional[int], kwargs.get("seed"))
job = self._qiskit_backend.run(
qcs,
Expand Down Expand Up @@ -442,6 +461,7 @@ def __init__(
self,
noise_model: Optional[NoiseModel] = None,
simulation_method: str = "automatic",
crosstalk_params: Optional[CrosstalkParams] = None,
n_qubits: int = 40,
):
"""Backend for running simulations on the Qiskit Aer QASM simulator.
Expand All @@ -452,6 +472,9 @@ def __init__(
https://qiskit.org/documentation/stubs/qiskit.providers.aer.AerSimulator.html
for available values. Defaults to "automatic".
:type simulation_method: str
:param crosstalk_params: Apply crosstalk noise simulation to the circuits before
execution. `noise_model` will be overwritten if this is given. Default to None.
:type: Optional[`CrosstalkParams`]
:param n_qubits: The maximum number of qubits supported by the backend.
"""
super().__init__()
Expand All @@ -462,41 +485,62 @@ def __init__(
gate_set = _tket_gate_set_from_qiskit_backend(self._qiskit_backend).union(
self._allowed_special_gates
)
self._noise_model = _map_trivial_noise_model_to_none(noise_model)
characterisation = _get_characterisation_of_noise_model(
self._noise_model, gate_set
)
self._has_arch = bool(characterisation.architecture) and bool(
characterisation.architecture.nodes
)

self._backend_info = BackendInfo(
name=type(self).__name__,
device_name=self._qiskit_backend_name,
version=__extension_version__,
architecture=characterisation.architecture
if self._has_arch
else FullyConnected(n_qubits),
gate_set=gate_set,
supports_midcircuit_measurement=True, # is this correct?
supports_fast_feedforward=True,
all_node_gate_errors=characterisation.node_errors,
all_edge_gate_errors=characterisation.edge_errors,
all_readout_errors=characterisation.readout_errors,
averaged_node_gate_errors=characterisation.averaged_node_errors,
averaged_edge_gate_errors=characterisation.averaged_edge_errors,
averaged_readout_errors=characterisation.averaged_readout_errors,
misc={"characterisation": characterisation.generic_q_errors},
)
self._crosstalk_params = crosstalk_params
if self._crosstalk_params is not None:
self._noise_model = self._crosstalk_params.get_noise_model()
self._backend_info = BackendInfo(
name=type(self).__name__,
device_name=self._qiskit_backend_name,
version=__extension_version__,
architecture=Architecture([]),
gate_set=gate_set,
)
else:
self._noise_model = _map_trivial_noise_model_to_none(noise_model)
characterisation = _get_characterisation_of_noise_model(
self._noise_model, gate_set
)
self._has_arch = bool(characterisation.architecture) and bool(
characterisation.architecture.nodes
)

self._backend_info = BackendInfo(
name=type(self).__name__,
device_name=self._qiskit_backend_name,
version=__extension_version__,
architecture=characterisation.architecture
if self._has_arch
else FullyConnected(n_qubits),
gate_set=gate_set,
supports_midcircuit_measurement=True, # is this correct?
supports_fast_feedforward=True,
all_node_gate_errors=characterisation.node_errors,
all_edge_gate_errors=characterisation.edge_errors,
all_readout_errors=characterisation.readout_errors,
averaged_node_gate_errors=characterisation.averaged_node_errors,
averaged_edge_gate_errors=characterisation.averaged_edge_errors,
averaged_readout_errors=characterisation.averaged_readout_errors,
misc={"characterisation": characterisation.generic_q_errors},
)

self._required_predicates = [
NoSymbolsPredicate(),
GateSetPredicate(self._backend_info.gate_set),
]
if self._crosstalk_params is not None:
self._required_predicates.extend(
[
NoClassicalControlPredicate(),
DefaultRegisterPredicate(),
NoBarriersPredicate(),
]
)

if self._has_arch:
# architecture is non-trivial
self._required_predicates.append(
ConnectivityPredicate(characterisation.architecture)
ConnectivityPredicate(self._backend_info.architecture) # type: ignore
)


Expand Down Expand Up @@ -545,6 +589,7 @@ class AerUnitaryBackend(_AerBaseBackend):

_memory = False
_noise_model = None
_needs_transpile = True

_qiskit_backend_name = "aer_simulator_unitary"

Expand Down
4 changes: 2 additions & 2 deletions pytket/extensions/qiskit/backends/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def set_ibmq_config(

config = QiskitConfig.from_default_config_file()
if instance is not None:
config.instance = instance # type: ignore
config.instance = instance
if ibmq_api_token is not None:
config.ibmq_api_token = ibmq_api_token # type: ignore
config.ibmq_api_token = ibmq_api_token
config.update_default_config_file()
Loading

0 comments on commit 4e5a073

Please sign in to comment.