qubrabench package

Subpackages

Submodules

qubrabench.benchmark module

exception qubrabench.benchmark.BenchmarkError

Bases: Exception

Base class for raising benchmarking errors

class qubrabench.benchmark.BlockEncoding(matrix: ndarray[Any, dtype[complex128]], subnormalization_factor: float, precision: float, uses: Iterable[tuple[Hashable, float]] = _Nothing.NOTHING)

Bases: QObject

Unitary that block-encodes an approximation of a (subnormalized version of a) matrix.

Given a matrix $A$, subnormalization factor $alpha$ and precision $epsilon$, this object represents a unitary program $U$ (possibly using ancilla) satisfying

\[\| A - \alpha (\langle 0 | \otimes I) U (|0\rangle \otimes I) \|_2 \le \epsilon\]

This can also be visualized as

\[\begin{split}U \approx \begin{pmatrix} A/\alpha & \cdot \\ \cdot & \cdot \end{pmatrix}\end{split}\]
access(*, n_times: int = 1)

Access the block-encoded matrix via the implementing unitary

costs: dict[Hashable, qubrabench.benchmark.QueryStats]
matrix: ndarray[Any, dtype[complex128]]

The block-encoded matrix A

precision: float

The spectral norm of the difference between the expected and actual encoded matrices.

If the top-left block of the unitary is $B$, then the precision is given by $| A - alpha B |_2$.

subnormalization_factor: float

Factor $alpha$ s.t. $A / alpha$ is block-encoded

uses: Iterable[tuple[Hashable, float]]

BlockEncodings or data-structures used to implement the block-encoding unitary

class qubrabench.benchmark.QObject

Bases: ABC, Hashable

A quantum data-structure object whose queries are tracked.

property stats: QueryStats
class qubrabench.benchmark.QueryStats(classical_actual_queries: int = 0, classical_expected_queries: float | NotComputed = 0.0, quantum_expected_classical_queries: float | NotComputed = 0.0, quantum_expected_quantum_queries: float | NotComputed = 0.0, quantum_worst_case_classical_queries: float | NotComputed = 0.0, quantum_worst_case_quantum_queries: float | NotComputed = 0.0)

Bases: object

Dataclass providing fields for different quantum and classical query counts. This is the main data model of the framework, holding actual and statistically calculated values.

classical_actual_queries: int = 0
classical_expected_queries: float | NotComputed = 0.0
quantum_expected_classical_queries: float | NotComputed = 0.0
quantum_expected_quantum_queries: float | NotComputed = 0.0
quantum_worst_case_classical_queries: float | NotComputed = 0.0
quantum_worst_case_quantum_queries: float | NotComputed = 0.0
property quantum_worst_case_total_queries: float | NotComputed

total number of queries in a unitary implementing the action, possibly using workspace (garbage) registers

record_query(n: int = 1)
qubrabench.benchmark.default_tracker()
qubrabench.benchmark.oracle(func: Callable[[_P], _R]) Callable[[_P], _R]

Wrapper to track queries for functions.

Usage:

@oracle
def some_func(*args, **kwargs):
    ...


with track_queries() as tracker:
    ...
    print(tracker.get_stats(some_func))

This can also be run with bound instance methods

class MyClass
    @oracle
    def some_method(self, *args, **kwargs):
        ...

    @classmethod
    @oracle
    def some_class_method(cls, *args, **kwargs):
        ...

    @staticmethod
    @oracle
    def some_static_method(*args, **kwargs):
        ...

with track_queries() as tracker:
    obj = MyClass()
    ...
    print(tracker.get_stats(obj.some_method))
    print(tracker.get_stats(obj.some_class_method))
    print(tracker.get_stats(obj.some_static_method))
qubrabench.benchmark.quantum_subroutine(func: Callable[[_P], BlockEncoding]) Callable[[_P], BlockEncoding]

Wrapper to mark a function as a quantum subroutine.

A quantum subroutine must return a BlockEncoding as output.

The wrapper ensures that all oracle calls are accounted for in the costs of the block-encoding, instead of throwing them to higher level tracker. This way, we can ensure that the costs when using the block-encoding are correct.

qubrabench.benchmark.track_queries() Iterator[BenchmarkFrame]

Track queries counts through the execution.

Usage:

with track_queries() as tracker:

# do some computation

print(tracker.get_stats(some_quantum_oracle)) print(tracker.get_stats(some_object_with_a_quantum_oracle_method))

Module contents

qubrabench.array(data) Qndarray
qubrabench.estimate_amplitude(x: BlockEncoding, good_indices: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes], *, precision: float, max_fail_probability: float) float

Given a block-encoding of a state $ketpsi$ and a good index or sequence of good indices, estimate the probability of measuring (in the standard basis) one of the good indices.

Algorithm analysis is described in Ref. [1], Theorem 12 (Amplitude Estimation).

When $ket{x} = sum_i alpha_i ket{i}$, then this method produces an estimate of $a$ s.t.

\[a = \sum_{i \in \text{good}} \abs{alpha_i}^2\]

If the input block-encoding does not perfectly prepare the state, but with some probability, this is factored into the subroutine in the quantum part (i.e. “under-the-square-root”)

Parameters:
  • x – block-encoded access to vector x, such as a unitary that prepares $ket{x}$ with some success probability

  • good_indices – index or sequence of indices for which to estimate the total squared amplitude

  • precision – upper bound on the difference between the estimate and true value

  • max_fail_probability – upper bound on the probability of failure of the quantum algorithm

References

[1] Quantum Amplitude Amplification and Estimation

Brassard, Hoyer, Mosca, Tapp. 2000. https://doi.org/10.48550/arXiv.quant-ph/0005055

qubrabench.max(iterable: ~typing.Iterable[~qubrabench.algorithms.max.E], *, max_fail_probability: float, default: ~qubrabench.algorithms.max.E | ~qubrabench._internals.AbsentParameter = <qubrabench._internals.AbsentParameter object>, key: ~typing.Callable[[~qubrabench.algorithms.max.E], ~typing.Any] | None = None) E

Find the largest element in a list.

Parameters:
  • iterable – iterable to find the maximum in

  • default – default value to return if iterable is empty.

  • key – function that maps iterable elements to values that are comparable. By default, use the iterable elements.

  • max_fail_probability – upper bound on the failure probability of the quantum algorithm.

Raises:

ValueError – Raised when iterable is an empty sequence and no default is provided.

Returns:

the desired maximum element

qubrabench.oracle(func: Callable[[_P], _R]) Callable[[_P], _R]

Wrapper to track queries for functions.

Usage:

@oracle
def some_func(*args, **kwargs):
    ...


with track_queries() as tracker:
    ...
    print(tracker.get_stats(some_func))

This can also be run with bound instance methods

class MyClass
    @oracle
    def some_method(self, *args, **kwargs):
        ...

    @classmethod
    @oracle
    def some_class_method(cls, *args, **kwargs):
        ...

    @staticmethod
    @oracle
    def some_static_method(*args, **kwargs):
        ...

with track_queries() as tracker:
    obj = MyClass()
    ...
    print(tracker.get_stats(obj.some_method))
    print(tracker.get_stats(obj.some_class_method))
    print(tracker.get_stats(obj.some_static_method))
qubrabench.search(iterable: Iterable[E], key: Callable[[E], bool], *, max_fail_probability: float, rng: Generator | None = None, max_classical_queries: int = 130) E | None

Search a list for an element satisfying the given predicate.

>>> search([1,2,3,4,5], lambda x: x % 2 == 0, max_fail_probability=1/3)
2

By default performs a linear scan on the iterable and returns the first element satisfying the key. If the optional random generator rng is provided, instead shuffles the input iterable before scanning for a solution.

>>> search([1,2,3,4,5], lambda x: x % 2 == 0, rng=np.random.default_rng(42), max_fail_probability=1/3)
4
Parameters:
  • iterable – iterable to be searched over

  • key – function to test if an element satisfies the predicate

  • max_fail_probability – upper bound on the failure probability of the quantum algorithm

  • rng – random generator - if provided shuffle the input before scanning

  • max_classical_queries – maximum number of classical queries before entering the quantum part of the algorithm

Returns:

An element that satisfies the predicate, or None if no such argument can be found.

qubrabench.track_queries() Iterator[BenchmarkFrame]

Track queries counts through the execution.

Usage:

with track_queries() as tracker:

# do some computation

print(tracker.get_stats(some_quantum_oracle)) print(tracker.get_stats(some_object_with_a_quantum_oracle_method))