Skip to content

Commit

Permalink
Fix algorithm mypy errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Randl committed Feb 15, 2023
1 parent e016f9c commit f5d0008
Show file tree
Hide file tree
Showing 79 changed files with 613 additions and 568 deletions.
46 changes: 25 additions & 21 deletions qiskit/algorithms/amplitude_amplifiers/amplification_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
# that they have been altered from the originals.

"""The Amplification problem class."""
from __future__ import annotations

from typing import Optional, Callable, Any, Union, List
from typing import Callable, Any

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import GroverOperator
Expand All @@ -29,14 +30,12 @@ class AmplificationProblem:

def __init__(
self,
oracle: Union[QuantumCircuit, Statevector],
state_preparation: Optional[QuantumCircuit] = None,
grover_operator: Optional[QuantumCircuit] = None,
post_processing: Optional[Callable[[str], Any]] = None,
objective_qubits: Optional[Union[int, List[int]]] = None,
is_good_state: Optional[
Union[Callable[[str], bool], List[int], List[str], Statevector]
] = None,
oracle: QuantumCircuit | Statevector,
state_preparation: QuantumCircuit | None = None,
grover_operator: QuantumCircuit | None = None,
post_processing: Callable[[str], Any] | None = None,
objective_qubits: int | list[int] | None = None,
is_good_state: Callable[[str], bool] | list[int] | list[str] | Statevector | None = None,
) -> None:
r"""
Args:
Expand All @@ -63,12 +62,12 @@ def __init__(
if is_good_state is not None:
self._is_good_state = is_good_state
elif hasattr(oracle, "evaluate_bitstring"):
self._is_good_state = oracle.evaluate_bitstring
self._is_good_state = oracle.evaluate_bitstring # type: ignore[union-attr]
else:
self._is_good_state = None

@property
def oracle(self) -> Union[QuantumCircuit, Statevector]:
def oracle(self) -> QuantumCircuit | Statevector:
"""Return the oracle.
Returns:
Expand All @@ -77,7 +76,7 @@ def oracle(self) -> Union[QuantumCircuit, Statevector]:
return self._oracle

@oracle.setter
def oracle(self, oracle: Union[QuantumCircuit, Statevector]) -> None:
def oracle(self, oracle: QuantumCircuit | Statevector) -> None:
"""Set the oracle.
Args:
Expand All @@ -100,7 +99,7 @@ def state_preparation(self) -> QuantumCircuit:
return self._state_preparation

@state_preparation.setter
def state_preparation(self, state_preparation: Optional[QuantumCircuit]) -> None:
def state_preparation(self, state_preparation: QuantumCircuit | None) -> None:
r"""Set the :math:`\mathcal{A}` operator. If None, a layer of Hadamard gates is used.
Args:
Expand Down Expand Up @@ -130,7 +129,7 @@ def post_processing(self, post_processing: Callable[[str], Any]) -> None:
self._post_processing = post_processing

@property
def objective_qubits(self) -> List[int]:
def objective_qubits(self) -> list[int]:
"""The indices of the objective qubits.
Returns:
Expand All @@ -145,7 +144,7 @@ def objective_qubits(self) -> List[int]:
return self._objective_qubits

@objective_qubits.setter
def objective_qubits(self, objective_qubits: Optional[Union[int, List[int]]]) -> None:
def objective_qubits(self, objective_qubits: int | list[int] | None) -> None:
"""Set the objective qubits.
Args:
Expand All @@ -167,18 +166,23 @@ def is_good_state(self) -> Callable[[str], bool]:
return self._is_good_state # returns None if no is_good_state arg has been set
elif isinstance(self._is_good_state, list):
if all(isinstance(good_bitstr, str) for good_bitstr in self._is_good_state):
return lambda bitstr: bitstr in self._is_good_state
return (
lambda bitstr: bitstr in self._is_good_state
) # error due to https://github.com/python/mypy/issues/4297
else:
return lambda bitstr: all(
bitstr[good_index] == "1" # type:ignore
bitstr[good_index] == "1" # type:ignore[index]
for good_index in self._is_good_state
)

return lambda bitstr: bitstr in self._is_good_state.probabilities_dict()
return (
lambda bitstr: bitstr
in self._is_good_state.probabilities_dict() # type:ignore[union-attr]
)

@is_good_state.setter
def is_good_state(
self, is_good_state: Union[Callable[[str], bool], List[int], List[str], Statevector]
self, is_good_state: Callable[[str], bool] | list[int] | list[str] | Statevector
) -> None:
"""Set the ``is_good_state`` function.
Expand All @@ -188,7 +192,7 @@ def is_good_state(
self._is_good_state = is_good_state

@property
def grover_operator(self) -> Optional[QuantumCircuit]:
def grover_operator(self) -> QuantumCircuit | None:
r"""Get the :math:`\mathcal{Q}` operator, or Grover operator.
If the Grover operator is not set, we try to build it from the :math:`\mathcal{A}` operator
Expand All @@ -203,7 +207,7 @@ def grover_operator(self) -> Optional[QuantumCircuit]:
return self._grover_operator

@grover_operator.setter
def grover_operator(self, grover_operator: Optional[QuantumCircuit]) -> None:
def grover_operator(self, grover_operator: QuantumCircuit | None) -> None:
r"""Set the :math:`\mathcal{Q}` operator.
If None, this operator is constructed from the ``oracle`` and ``state_preparation``.
Expand Down
17 changes: 9 additions & 8 deletions qiskit/algorithms/amplitude_amplifiers/amplitude_amplifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
# that they have been altered from the originals.

"""The interface for amplification algorithms and results."""
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Optional, Any, Union, Dict, List
from typing import Any

import numpy as np

Expand Down Expand Up @@ -43,14 +44,14 @@ class AmplitudeAmplifierResult(AlgorithmResult):

def __init__(self) -> None:
super().__init__()
self._top_measurement = None
self._top_measurement: str | None = None
self._assignment = None
self._oracle_evaluation = None
self._circuit_results = None
self._max_probability = None
self._oracle_evaluation: bool | None = None
self._circuit_results: list[np.ndarray] | list[dict[str, int]] | None = None
self._max_probability: float | None = None

@property
def top_measurement(self) -> Optional[str]:
def top_measurement(self) -> str | None:
"""The most frequently measured output as bitstring.
Returns:
Expand Down Expand Up @@ -106,12 +107,12 @@ def oracle_evaluation(self, value: bool) -> None:
self._oracle_evaluation = value

@property
def circuit_results(self) -> Optional[Union[List[np.ndarray], List[Dict[str, int]]]]:
def circuit_results(self) -> list[np.ndarray] | list[dict[str, int]] | None:
"""Return the circuit results. Can be a statevector or counts dictionary."""
return self._circuit_results

@circuit_results.setter
def circuit_results(self, value: Union[List[np.ndarray], List[Dict[str, int]]]) -> None:
def circuit_results(self, value: list[np.ndarray] | list[dict[str, int]]) -> None:
"""Set the circuit results."""
self._circuit_results = value

Expand Down
40 changes: 23 additions & 17 deletions qiskit/algorithms/amplitude_amplifiers/grover.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@
# that they have been altered from the originals.

"""Grover's search algorithm."""
from __future__ import annotations

import itertools
import operator
import warnings
from typing import Iterator, List, Optional, Union
from typing import Iterator, cast, Any, Dict

import numpy as np

from qiskit import ClassicalRegister, QuantumCircuit
from qiskit.algorithms.exceptions import AlgorithmError
from qiskit.primitives import BaseSampler
from qiskit.providers import Backend
from qiskit.quantum_info import partial_trace
from qiskit.quantum_info import partial_trace, Statevector
from qiskit.utils import QuantumInstance, algorithm_globals
from qiskit.utils.deprecation import deprecate_function

Expand Down Expand Up @@ -114,11 +115,11 @@ class Grover(AmplitudeAmplifier):

def __init__(
self,
iterations: Optional[Union[List[int], Iterator[int], int]] = None,
growth_rate: Optional[float] = None,
iterations: list[int] | Iterator[int] | int | None = None,
growth_rate: float | None = None,
sample_from_iterations: bool = False,
quantum_instance: Optional[Union[QuantumInstance, Backend]] = None,
sampler: Optional[BaseSampler] = None,
quantum_instance: QuantumInstance | Backend | None = None,
sampler: BaseSampler | None = None,
) -> None:
r"""
Args:
Expand Down Expand Up @@ -157,7 +158,9 @@ def __init__(

if growth_rate is not None:
# yield iterations ** 1, iterations ** 2, etc. and casts to int
self._iterations = map(lambda x: int(growth_rate**x), itertools.count(1))
self._iterations: list[int] | Iterator[int] | None = map(
lambda x: int(growth_rate**x), itertools.count(1)
)
elif isinstance(iterations, int):
self._iterations = [iterations]
else:
Expand All @@ -172,7 +175,7 @@ def __init__(
sampler = quantum_instance
quantum_instance = None

self._quantum_instance = None
self._quantum_instance: QuantumInstance | None = None
if quantum_instance is not None:
warnings.warn(
"The quantum_instance argument has been superseded by the sampler argument. "
Expand All @@ -197,7 +200,7 @@ def __init__(
"removed after that.",
category=PendingDeprecationWarning,
)
def quantum_instance(self) -> Optional[QuantumInstance]:
def quantum_instance(self) -> QuantumInstance | None:
r"""Pending deprecation\; Get the quantum instance.
Returns:
Expand All @@ -212,7 +215,7 @@ def quantum_instance(self) -> Optional[QuantumInstance]:
"removed after that.",
category=PendingDeprecationWarning,
)
def quantum_instance(self, quantum_instance: Union[QuantumInstance, Backend]) -> None:
def quantum_instance(self, quantum_instance: QuantumInstance | Backend) -> None:
r"""Pending deprecation\; Set quantum instance.
Args:
Expand All @@ -223,7 +226,7 @@ def quantum_instance(self, quantum_instance: Union[QuantumInstance, Backend]) ->
self._quantum_instance = quantum_instance

@property
def sampler(self) -> Optional[BaseSampler]:
def sampler(self) -> BaseSampler | None:
"""Get the sampler.
Returns:
Expand Down Expand Up @@ -265,7 +268,7 @@ def amplify(self, amplification_problem: AmplificationProblem) -> "GroverResult"
if isinstance(self._iterations, list):
max_iterations = len(self._iterations)
max_power = np.inf # no cap on the power
iterator = iter(self._iterations)
iterator: Iterator[int] = iter(self._iterations)
else:
max_iterations = max(10, 2**amplification_problem.oracle.num_qubits)
max_power = np.ceil(
Expand Down Expand Up @@ -305,15 +308,18 @@ def amplify(self, amplification_problem: AmplificationProblem) -> "GroverResult"
raise AlgorithmError("Sampler job failed.") from exc

num_bits = len(amplification_problem.objective_qubits)
circuit_results = {
circuit_results: dict[str, Any] | Statevector | np.ndarray = {
np.binary_repr(k, num_bits): v for k, v in results.quasi_dists[0].items()
}
circuit_results = cast(Dict[str, Any], circuit_results)
top_measurement, max_probability = max(circuit_results.items(), key=lambda x: x[1])

else: # use of else brach instead of elif as this seperates out the deprecated logic
if self._quantum_instance.is_statevector:
qc = self.construct_circuit(amplification_problem, power, measurement=False)
circuit_results = self._quantum_instance.execute(qc).get_statevector()
circuit_results = cast(Statevector | np.ndarray, circuit_results)

num_bits = len(amplification_problem.objective_qubits)

# trace out work qubits
Expand Down Expand Up @@ -384,7 +390,7 @@ def optimal_num_iterations(num_solutions: int, num_qubits: int) -> int:
return round(np.arccos(amplitude) / (2 * np.arcsin(amplitude)))

def construct_circuit(
self, problem: AmplificationProblem, power: Optional[int] = None, measurement: bool = False
self, problem: AmplificationProblem, power: int | None = None, measurement: bool = False
) -> QuantumCircuit:
"""Construct the circuit for Grover's algorithm with ``power`` Grover operators.
Expand Down Expand Up @@ -423,10 +429,10 @@ class GroverResult(AmplitudeAmplifierResult):

def __init__(self) -> None:
super().__init__()
self._iterations = None
self._iterations: list[int] | None = None

@property
def iterations(self) -> List[int]:
def iterations(self) -> list[int]:
"""All the powers of the Grover operator that have been tried.
Returns:
Expand All @@ -435,7 +441,7 @@ def iterations(self) -> List[int]:
return self._iterations

@iterations.setter
def iterations(self, value: List[int]) -> None:
def iterations(self, value: list[int]) -> None:
"""Set the powers of the Grover operator that have been tried.
Args:
Expand Down
22 changes: 12 additions & 10 deletions qiskit/algorithms/amplitude_estimators/ae.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def estimate(self, estimation_problem: EstimationProblem) -> "AmplitudeEstimatio
# store the number of oracle queries
result.num_oracle_queries = result.shots * (self._M - 1)

# run the MLE post processing
# run the MLE post-processing
mle = self.compute_mle(result)
result.mle = mle
result.mle_processed = estimation_problem.post_processing(mle)
Expand Down Expand Up @@ -468,13 +468,13 @@ class AmplitudeEstimationResult(AmplitudeEstimatorResult):

def __init__(self) -> None:
super().__init__()
self._num_evaluation_qubits = None
self._mle = None
self._mle_processed = None
self._samples = None
self._samples_processed = None
self._y_measurements = None
self._max_probability = None
self._num_evaluation_qubits: int | None = None
self._mle: float | None = None
self._mle_processed: float | None = None
self._samples: dict[float, float] | None = None
self._samples_processed: dict[float, float] | None = None
self._y_measurements: dict[int, float] | None = None
self._max_probability: float | None = None

@property
def num_evaluation_qubits(self) -> int:
Expand Down Expand Up @@ -582,7 +582,7 @@ def integrand(x):

def _fisher_confint(
result: AmplitudeEstimationResult, alpha: float, observed: bool = False
) -> list[float]:
) -> tuple[float, float]:
"""Compute the Fisher information confidence interval for the MLE of the previous run.
Args:
Expand All @@ -602,7 +602,9 @@ def _fisher_confint(
return tuple(result.post_processing(bound) for bound in confint)


def _likelihood_ratio_confint(result: AmplitudeEstimationResult, alpha: float) -> list[float]:
def _likelihood_ratio_confint(
result: AmplitudeEstimationResult, alpha: float
) -> tuple[float, float]:
"""Compute the likelihood ratio confidence interval for the MLE of the previous run.
Args:
Expand Down
16 changes: 8 additions & 8 deletions qiskit/algorithms/amplitude_estimators/amplitude_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ class AmplitudeEstimatorResult(AlgorithmResult):

def __init__(self) -> None:
super().__init__()
self._circuit_results = None
self._shots = None
self._estimation = None
self._estimation_processed = None
self._num_oracle_queries = None
self._post_processing = None
self._confidence_interval = None
self._confidence_interval_processed = None
self._circuit_results: np.ndarray | dict[str, int] | None = None
self._shots: int | None = None
self._estimation: float | None = None
self._estimation_processed: float | None = None
self._num_oracle_queries: int | None = None
self._post_processing: Callable[[float], float] | None = None
self._confidence_interval: tuple[float, float] | None = None
self._confidence_interval_processed: tuple[float, float] | None = None

@property
def circuit_results(self) -> np.ndarray | dict[str, int] | None:
Expand Down
Loading

0 comments on commit f5d0008

Please sign in to comment.