Skip to content

Commit

Permalink
Merge 45b9ee1 into d429015
Browse files Browse the repository at this point in the history
  • Loading branch information
airwoodix committed Jun 21, 2024
2 parents d429015 + 45b9ee1 commit 2953816
Show file tree
Hide file tree
Showing 15 changed files with 145 additions and 94 deletions.
12 changes: 9 additions & 3 deletions examples/number_partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,23 @@

@dataclass(frozen=True)
class Success:
"""Solution of a partition problem."""

# type would be better as tuple[set[int], set[int]] but
# NumberPartition.interpret returns list[list[int]].
partition: list[list[int]]

def verify(self) -> bool:
def is_valid(self) -> bool:
"""Evaluate whether the stored partition is valid.
A partition is valid if both sets have the same sum.
"""
a, b = self.partition
return sum(a) == sum(b)


class Infeasible:
pass
"""Marker for unsolvable partition problems."""


def solve_partition_problem(num_set: set[int]) -> Union[Success, Infeasible]:
Expand Down Expand Up @@ -87,7 +93,7 @@ def solve_partition_problem(num_set: set[int]) -> Union[Success, Infeasible]:
num_set = {1, 3, 4}
result = solve_partition_problem(num_set)
assert isinstance(result, Success) # noqa: S101
assert result.verify() # noqa: S101
assert result.is_valid() # noqa: S101
print(f"Partition for {num_set}:", result.partition)

num_set = {1, 2}
Expand Down
16 changes: 13 additions & 3 deletions examples/quickstart-estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
the ground state energy of a Hamiltonian.
"""

from collections.abc import Sequence

from qiskit import QuantumCircuit
from qiskit.circuit.library import TwoLocal
from qiskit.primitives import BaseEstimator
from qiskit.quantum_info import SparsePauliOp
from qiskit.quantum_info.operators.base_operator import BaseOperator
from scipy.optimize import minimize

from qiskit_aqt_provider import AQTProvider
Expand Down Expand Up @@ -48,16 +53,21 @@

# Define the VQE Ansatz, initial point, and cost function
ansatz = TwoLocal(num_qubits=2, rotation_blocks="ry", entanglement_blocks="cz")
initial_point = initial_point = [0] * 8
initial_point = [0] * 8


def cost_function(params, ansatz, hamiltonian, estimator):
def cost_function(
params: Sequence[float],
ansatz: QuantumCircuit,
hamiltonian: BaseOperator,
estimator: BaseEstimator,
) -> float:
"""Cost function for the VQE.
Return the estimated expectation value of the Hamiltonian
on the state prepared by the Ansatz circuit.
"""
return estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0]
return float(estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0])


# Run the VQE using the SciPy minimizer routine
Expand Down
107 changes: 56 additions & 51 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,63 +119,67 @@ extend-exclude = [
]

lint.select = [
"ARG", # flake8-unused-arguments
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
"C90", # mccabe
"COM", # flake8-commas
"D", # pydocstyle
"E", # pycodestyle errors
"ERA", # eradicate
"F", # pyflakes
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"NPY", # numpy
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"PYI", # flake8-pyi
"RET", # flake8-return
"RSE", # flake8-raise
"RUF", # ruff specials
"S", # flake8-bandit
"SIM", # flake8-simplify
"T10", # flake8-debugger
"T20", # flake8-print
"TID", # flake8-tidy-imports
"UP", # pyupgrade
"W", # pycodestyle warnings
"ANN", # flake8-annotations
"ARG", # flake8-unused-arguments
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
"C90", # mccabe
"COM", # flake8-commas
"D", # pydocstyle
"E", # pycodestyle errors
"ERA", # eradicate
"EXE", # flake8-executable
"F", # pyflakes
"FLY", # flynt
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"NPY", # numpy
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"PYI", # flake8-pyi
"RET", # flake8-return
"RSE", # flake8-raise
"RUF", # ruff specials
"S", # flake8-bandit
"SIM", # flake8-simplify
"SLOT", # flake8-slots
"T10", # flake8-debugger
"T20", # flake8-print
"TID", # flake8-tidy-imports
"UP", # pyupgrade
"W", # pycodestyle warnings
"YTT", # flake8-2020
]
lint.ignore = [
"COM812",
"COM819",
"ANN101", # missing-type-self (deprecated)
"ANN102", # missing-type-cls (deprecated)
"ANN401", # any-type
"COM812", # missing-trailing-comma
"COM819", # prohibited-trailing-comma
"D100", # missing docstring in public module
"D101", # missing docstring in public class
"D102", # missing docstring in public method
"D104", # missing docstring in public package
"D107", # missing docstring in __init__
"D206",
"D206", # indent-with-spaces
"D211", # no-blank-line-before-class (incompatible with D203)
"D213", # multiline-summary-second-line (incompatible with D212)
"D300",
"E111",
"E114",
"E117",
"E501",
"ISC001",
"ISC002",
"Q000",
"Q001",
"Q002",
"Q003",
"D300", # triple-single-quotes
"E111", # indentation-with-invalid-multiple
"E114", # indentation-with-invalid-multiple-comment
"E117", # over-idented
"ISC001", # single-line-implicit-string-concatenation
"ISC002", # multi-line-implicit-string-concatenation
"Q000", # bad-quotes-inline-string
"Q001", # bad-quotes-multiline-string
"Q002", # bad-quotes-docstring
"Q003", # avoidable-escaped-quote
"S311", # suspicious-non-cryptographic-random-usage
"SIM117", # multiple-with-statements
#
# ignore following rules since they are conflicting with the formatter
# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
"W191",
"W191", # tab-indentation
]
lint.per-file-ignores."examples/*.py" = [
"T201", # allow prints
Expand All @@ -184,9 +188,10 @@ lint.per-file-ignores."scripts/*.py" = [
"T201", # allow prints
]
lint.per-file-ignores."test/**/*.py" = [
"D205", # allow multiline docstring summaries
"PT011", # allow pytest.raises without match=
"S101", # allow assertions
"D205", # allow multiline docstring summaries
"PLR2004", # magic-value-comparison
"PT011", # allow pytest.raises without match=
"S101", # allow assertions
]
lint.pydocstyle.convention = "google"

Expand Down
17 changes: 13 additions & 4 deletions qiskit_aqt_provider/aqt_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from collections import Counter, defaultdict
from dataclasses import dataclass
from pathlib import Path
from types import TracebackType
from typing import (
TYPE_CHECKING,
Any,
Expand Down Expand Up @@ -111,7 +112,13 @@ def update(self, n: int = 1) -> None:
def __enter__(self) -> Self:
return self

def __exit__(*args) -> None: ...
def __exit__(
self,
exc_type: Optional[type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType],
/,
) -> None: ...


class AQTJob(JobV1):
Expand Down Expand Up @@ -153,7 +160,7 @@ def __init__(
backend: "AQTResource",
circuits: list[QuantumCircuit],
options: AQTOptions,
):
) -> None:
"""Initialize an :class:`AQTJob` instance.
.. tip:: :class:`AQTJob` instances should not be created directly. Use
Expand Down Expand Up @@ -389,7 +396,9 @@ def callback(
class AQTDirectAccessJob(JobV1):
"""Handle for quantum circuits jobs running on direct-access AQT backends.
Use :meth:`AQTDirectAccessResource.run <qiskit_aqt_provider.aqt_resource.AQTDirectAccessResource.run>`
Use
:meth:`AQTDirectAccessResource.run
<qiskit_aqt_provider.aqt_resource.AQTDirectAccessResource.run>`
to get a handle and evaluate circuits on a direct-access backend.
"""

Expand All @@ -400,7 +409,7 @@ def __init__(
backend: "AQTDirectAccessResource",
circuits: list[QuantumCircuit],
options: AQTOptions,
):
) -> None:
"""Initialize the :class:`AQTDirectAccessJob` instance.
Args:
Expand Down
8 changes: 4 additions & 4 deletions qiskit_aqt_provider/aqt_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class AQTOptions(pdt.BaseModel, Mapping[str, Any]):
Option overrides can also be applied on a per-job basis, as keyword arguments to
:meth:`AQTResource.run <qiskit_aqt_provider.aqt_resource.AQTResource.run>` or
:meth:`AQTDirectAccessResource.run <qiskit_aqt_provider.aqt_resource.AQTDirectAccessResource.run>`:
:meth:`AQTDirectAccessResource.run
<qiskit_aqt_provider.aqt_resource.AQTDirectAccessResource.run>`:
>>> backend.options.shots
50
Expand Down Expand Up @@ -132,9 +133,8 @@ def max_shots(cls) -> int:

if isinstance(metadata, annotated_types.Lt): # pragma: no cover
return int(str(metadata.lt)) - 1
else: # pragma: no cover
msg = "No upper bound found for 'shots'."
raise ValueError(msg)

raise ValueError("No upper bound found for 'shots'.") # pragma: no cover


class AQTDirectAccessOptions(AQTOptions):
Expand Down
35 changes: 18 additions & 17 deletions qiskit_aqt_provider/aqt_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class BackendsTable(Sequence[AQTResource]):
in IPython/Jupyter notebooks.
"""

def __init__(self, backends: list[AQTResource]):
def __init__(self, backends: list[AQTResource]) -> None:
"""Initialize the table.
Args:
Expand Down Expand Up @@ -154,7 +154,7 @@ def __init__(
*,
load_dotenv: bool = True,
dotenv_path: Optional[StrPath] = None,
):
) -> None:
"""Initialize the AQT provider.
The access token for the AQT cloud can be provided either through the
Expand Down Expand Up @@ -269,22 +269,23 @@ def backends(
)
)

# add (filtered) remote resources
for _workspace in remote_workspaces.root:
for resource in _workspace.resources:
backends.append(
AQTResource(
self,
resource_id=api_models.ResourceId(
workspace_id=_workspace.id,
resource_id=resource.id,
resource_name=resource.name,
resource_type=resource.type.value,
),
)
return BackendsTable(
backends
# add (filtered) remote resources
+ [
AQTResource(
self,
resource_id=api_models.ResourceId(
workspace_id=_workspace.id,
resource_id=resource.id,
resource_name=resource.name,
resource_type=resource.type.value,
),
)

return BackendsTable(backends)
for _workspace in remote_workspaces.root
for resource in _workspace.resources
]
)

def get_backend(
self,
Expand Down
18 changes: 12 additions & 6 deletions qiskit_aqt_provider/aqt_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ def make_transpiler_target(target_cls: type[TargetT], num_qubits: int) -> Target
class _ResourceBase(Generic[_OptionsType], Backend):
"""Common setup for AQT backends."""

def __init__(self, provider: "AQTProvider", name: str, options_type: type[_OptionsType]):
def __init__(
self, provider: "AQTProvider", name: str, options_type: type[_OptionsType]
) -> None:
"""Initialize the Qiskit backend.
Args:
Expand Down Expand Up @@ -206,7 +208,7 @@ def __init__(
self,
provider: "AQTProvider",
resource_id: api_models.ResourceId,
):
) -> None:
"""Initialize the backend.
Args:
Expand Down Expand Up @@ -281,7 +283,9 @@ def result(self, job_id: UUID) -> api_models.JobResponse:
class AQTDirectAccessResource(_ResourceBase[AQTDirectAccessOptions]):
"""Qiskit backend for AQT direct-access quantum computing resources.
Use :meth:`AQTProvider.get_direct_access_backend <qiskit_aqt_provider.aqt_provider.AQTProvider.get_direct_access_backend>`
Use
:meth:`AQTProvider.get_direct_access_backend
<qiskit_aqt_provider.aqt_provider.AQTProvider.get_direct_access_backend>`
to retrieve backend instances.
"""

Expand Down Expand Up @@ -310,7 +314,8 @@ def run(
"""Prepare circuits for execution on this resource.
.. warning:: The circuits are only evaluated during
the :meth:`AQTDirectAccessJob.result <qiskit_aqt_provider.aqt_job.AQTDirectAccessJob.result>`
the :meth:`AQTDirectAccessJob.result
<qiskit_aqt_provider.aqt_job.AQTDirectAccessJob.result>`
call.
Args:
Expand Down Expand Up @@ -416,8 +421,9 @@ class OfflineSimulatorResource(AQTResource):
`with_noise_model` is true, a noise model approximating that of AQT hardware backends is used.
.. tip::
The simulator backend is provided by `Qiskit Aer <https://qiskit.github.io/qiskit-aer//>`_. The
Qiskit Aer resource is exposed for detailed detuning as the
The simulator backend is provided by
`Qiskit Aer <https://qiskit.github.io/qiskit-aer/>`_.
The Qiskit Aer resource is exposed for detailed detuning as the
``OfflineSimulatorResource.simulator`` attribute.
"""

Expand Down
2 changes: 1 addition & 1 deletion qiskit_aqt_provider/primitives/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(
options: Optional[dict[str, Any]] = None,
abelian_grouping: bool = True,
skip_transpilation: bool = False,
):
) -> None:
"""Initialize an ``Estimator`` primitive using an AQT backend.
See :class:`AQTSampler <qiskit_aqt_provider.primitives.sampler.AQTSampler>` for
Expand Down
Loading

0 comments on commit 2953816

Please sign in to comment.