diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 448dfbd..d33fa06 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -132,7 +132,7 @@ jobs: mkdir extensions ./build-docs -d ${GITHUB_WORKSPACE}/.github/workflows/docs/extensions/api - name: Upload docs as artefact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v2 with: path: .github/workflows/docs/extensions diff --git a/_metadata.py b/_metadata.py index 9ae6c72..5883064 100644 --- a/_metadata.py +++ b/_metadata.py @@ -1,2 +1,2 @@ -__extension_version__ = "0.29.0" +__extension_version__ = "0.30.0" __extension_name__ = "pytket-qulacs" diff --git a/docs/changelog.rst b/docs/changelog.rst index c857a39..0e18041 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ~~~~~~~~~ +0.30.0 (September 2023) +----------------------- + +* Allow setting of rng seed in qulacs backend. +* Updated pytket version requirement to 1.19. + 0.29.0 (June 2023) ------------------ diff --git a/pytket/extensions/qulacs/backends/qulacs_backend.py b/pytket/extensions/qulacs/backends/qulacs_backend.py index 859383e..552af9b 100644 --- a/pytket/extensions/qulacs/backends/qulacs_backend.py +++ b/pytket/extensions/qulacs/backends/qulacs_backend.py @@ -15,8 +15,9 @@ """Methods to allow tket circuits to be ran on the Qulacs simulator """ -from typing import List, Optional, Sequence, Union +from typing import List, Optional, Sequence, Union, cast from logging import warning +from random import Random from uuid import uuid4 import numpy as np from sympy import Expr # type: ignore @@ -181,6 +182,9 @@ def process_circuits( if valid_check: self._check_all_circuits(circuits, nomeasure_warn=False) + seed = cast(Optional[int], kwargs.get("seed")) + rng = Random(seed) if seed else None + handle_list = [] for circuit, n_shots_circ in zip(circuits, n_shots_list): qulacs_state = self._sim(circuit.n_qubits) @@ -205,7 +209,9 @@ def process_circuits( else: bits, choose_indices = zip(*bits2index) - samples = qulacs_state.sampling(n_shots_circ) + samples = self._sample_quantum_state( + qulacs_state, n_shots_circ, rng + ) shots = OutcomeArray.from_ints(samples, circuit.n_qubits) shots = shots.choose_indices(choose_indices) try: @@ -228,6 +234,14 @@ def process_circuits( del qulacs_circ return handle_list + def _sample_quantum_state( + self, quantum_state: QuantumState, n_shots: int, rng: Optional[Random] + ) -> List[int]: + if rng: + return quantum_state.sampling(n_shots, rng.randint(0, 2**32 - 1)) + else: + return quantum_state.sampling(n_shots) + def circuit_status(self, handle: ResultHandle) -> CircuitStatus: if handle in self._cache: return CircuitStatus(StatusEnum.COMPLETED) diff --git a/setup.py b/setup.py index 01fe572..dcfee89 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ license="Apache 2", packages=find_namespace_packages(include=["pytket.*"]), include_package_data=True, - install_requires=["pytket ~= 1.16", "qulacs ~= 0.6.0"], + install_requires=["pytket ~= 1.19", "qulacs ~= 0.6.0"], classifiers=[ "Environment :: Console", "Programming Language :: Python :: 3.9", diff --git a/tests/test_qulacs_backend.py b/tests/test_qulacs_backend.py index 8e251ff..2244bb2 100644 --- a/tests/test_qulacs_backend.py +++ b/tests/test_qulacs_backend.py @@ -13,6 +13,7 @@ # limitations under the License. from collections import Counter +from typing import List, Sequence, Union, Optional import warnings import math from hypothesis import given, strategies @@ -20,18 +21,43 @@ import pytest from openfermion.ops import QubitOperator # type: ignore from openfermion.linalg import eigenspectrum # type: ignore +from pytket.backends import ResultHandle from pytket.circuit import Circuit, BasisOrder, OpType, Qubit # type: ignore from pytket.pauli import Pauli, QubitPauliString # type: ignore from pytket.passes import CliffordSimp # type: ignore from pytket.utils.operators import QubitPauliOperator +from pytket.utils.results import KwargTypes from pytket.extensions.qulacs import QulacsBackend -backends = [QulacsBackend()] + +def make_seeded_QulacsBackend(base: type[QulacsBackend]) -> type: + class SeededQulacsBackend(base): # type: ignore + def __init__(self, seed: int): + base.__init__(self) + self._seed = seed + + def process_circuits( + self, + circuits: Sequence[Circuit], + n_shots: Union[None, int, Sequence[Optional[int]]] = None, + valid_check: bool = True, + **kwargs: KwargTypes + ) -> List[ResultHandle]: + if not "seed" in kwargs: + kwargs["seed"] = self._seed + return base.process_circuits(self, circuits, n_shots, valid_check, **kwargs) + + return SeededQulacsBackend + + +backends = [QulacsBackend(), make_seeded_QulacsBackend(QulacsBackend)(-1)] try: from pytket.extensions.qulacs import QulacsGPUBackend - backends.append(QulacsGPUBackend()) + backends.extend( + [QulacsGPUBackend(), make_seeded_QulacsBackend(QulacsGPUBackend)(1)] + ) except ImportError: warnings.warn("local settings failed to import QulacsGPUBackend", ImportWarning) @@ -266,7 +292,6 @@ def test_shots_bits_edgecases(n_shots, n_bits) -> None: c = Circuit(n_bits, n_bits) for qulacs_backend in backends: - # TODO TKET-813 add more shot based backends and move to integration tests h = qulacs_backend.process_circuit(c, n_shots) res = qulacs_backend.get_result(h)