Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
Add Grover and QAE result classes (#1219)
Browse files Browse the repository at this point in the history
* Add Grover and QAE result classes

* Update qiskit/aqua/algorithms/amplitude_estimators/mlae.py

Co-authored-by: Julien Gacon <[email protected]>

* Change return from Union[None, ...] to Optional[...]

* Combine statevector and counts into cct_result

* change names

Co-authored-by: Julien Gacon <[email protected]>
  • Loading branch information
manoelmarques and Cryoris authored Sep 10, 2020
1 parent 0b10c82 commit 2be89c1
Show file tree
Hide file tree
Showing 21 changed files with 546 additions and 64 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ backend = Aer.get_backend('qasm_simulator')
oracle = LogicalExpressionOracle(sat_cnf)
algorithm = Grover(oracle)
result = algorithm.run(backend)
print(result["result"])
print(result.assignment)
```

The code above demonstrates how `Grover`’s search algorithm can be used with the
Expand Down Expand Up @@ -308,8 +308,8 @@ num_eval_qubits = 5
algo = AmplitudeEstimation(num_eval_qubits, fixed_income)
result = algo.run(BasicAer.get_backend('statevector_simulator'))

print('Estimated value:\t%.4f' % result['estimation'])
print('Probability: \t%.4f' % result['max_probability'])
print('Estimated value:\t%.4f' % result.estimation)
print('Probability: \t%.4f' % result.max_probability)
```
When running the above the estimated value result should be 2.46 and probability 0.8487.

Expand Down
15 changes: 13 additions & 2 deletions qiskit/aqua/algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
:nosignatures:
Grover
GroverResult
Amplitude Estimators
++++++++++++++++++++
Expand All @@ -71,8 +72,11 @@
:nosignatures:
AmplitudeEstimation
AmplitudeEstimationResult
IterativeAmplitudeEstimation
IterativeAmplitudeEstimationResult
MaximumLikelihoodAmplitudeEstimation
MaximumLikelihoodAmplitudeEstimationResult
Classifiers
+++++++++++
Expand Down Expand Up @@ -179,10 +183,13 @@
from .quantum_algorithm import QuantumAlgorithm
from .classical_algorithm import ClassicalAlgorithm
from .vq_algorithm import VQAlgorithm, VQResult
from .amplitude_amplifiers import Grover
from .amplitude_amplifiers import Grover, GroverResult
from .amplitude_estimators import (AmplitudeEstimation,
AmplitudeEstimationResult,
IterativeAmplitudeEstimation,
MaximumLikelihoodAmplitudeEstimation)
IterativeAmplitudeEstimationResult,
MaximumLikelihoodAmplitudeEstimation,
MaximumLikelihoodAmplitudeEstimationResult)
from .classifiers import VQC, QSVM, SklearnSVM, SVM_Classical
from .distribution_learners import QGAN
from .eigen_solvers import NumPyEigensolver, ExactEigensolver, EigensolverResult
Expand Down Expand Up @@ -219,13 +226,17 @@
'EOH',
'QSVM',
'Grover',
'GroverResult',
'IQPE',
'IQPEResult',
'QPE',
'QPEResult',
'AmplitudeEstimation',
'AmplitudeEstimationResult',
'IterativeAmplitudeEstimation',
'IterativeAmplitudeEstimationResult',
'MaximumLikelihoodAmplitudeEstimation',
'MaximumLikelihoodAmplitudeEstimationResult',
'Simon',
'DeutschJozsa',
'BernsteinVazirani',
Expand Down
4 changes: 2 additions & 2 deletions qiskit/aqua/algorithms/amplitude_amplifiers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@

""" Amplitude Amplifiers Package """

from .grover import Grover
from .grover import Grover, GroverResult

__all__ = ['Grover']
__all__ = ['Grover', 'GroverResult']
86 changes: 82 additions & 4 deletions qiskit/aqua/algorithms/amplitude_amplifiers/grover.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
The Grover's Search algorithm.
"""

from typing import Optional, Union, Dict, Any
from typing import Optional, Union, Dict, Any, List
import logging
import warnings
import operator
import numpy as np

Expand All @@ -25,7 +26,7 @@
from qiskit.aqua import QuantumInstance, AquaError
from qiskit.aqua.utils import get_subsystem_density_matrix
from qiskit.aqua.utils.validation import validate_min, validate_in_set
from qiskit.aqua.algorithms import QuantumAlgorithm
from qiskit.aqua.algorithms import QuantumAlgorithm, AlgorithmResult
from qiskit.aqua.components.initial_states import Custom
from qiskit.aqua.components.oracles import Oracle
from qiskit.aqua.components.initial_states import InitialState
Expand Down Expand Up @@ -267,7 +268,7 @@ def construct_circuit(self, measurement=False):
self._ret['circuit'] = qc
return qc

def _run(self):
def _run(self) -> 'GroverResult':
if self._incremental:

def _try_target_num_iterations():
Expand Down Expand Up @@ -297,6 +298,83 @@ def _try_target_num_iterations():
self._qc_amplitude_amplification = QuantumCircuit()
assignment, oracle_evaluation = self._run_with_existing_iterations()

# TODO remove all former dictionary logic
self._ret['result'] = assignment
self._ret['oracle_evaluation'] = oracle_evaluation
return self._ret

result = GroverResult()
if 'measurement' in self._ret:
result.measurement = dict(self._ret['measurement'])
if 'top_measurement' in self._ret:
result.top_measurement = self._ret['top_measurement']
if 'circuit' in self._ret:
result.circuit = self._ret['circuit']
result.assignment = self._ret['result']
result.oracle_evaluation = self._ret['oracle_evaluation']
return result


class GroverResult(AlgorithmResult):
""" Grover Result."""

@property
def measurement(self) -> Optional[Dict[str, int]]:
""" returns measurement """
return self.get('measurement')

@measurement.setter
def measurement(self, value: Dict[str, int]) -> None:
""" set measurement """
self.data['measurement'] = value

@property
def top_measurement(self) -> Optional[str]:
""" return top measurement """
return self.get('top_measurement')

@top_measurement.setter
def top_measurement(self, value: str) -> None:
""" set top measurement """
self.data['top_measurement'] = value

@property
def circuit(self) -> Optional[QuantumCircuit]:
""" return circuit """
return self.get('circuit')

@circuit.setter
def circuit(self, value: QuantumCircuit) -> None:
""" set circuit """
self.data['circuit'] = value

@property
def assignment(self) -> List[int]:
""" return assignment """
return self.get('assignment')

@assignment.setter
def assignment(self, value: List[int]) -> None:
""" set assignment """
self.data['assignment'] = value

@property
def oracle_evaluation(self) -> bool:
""" return oracle evaluation """
return self.get('oracle_evaluation')

@oracle_evaluation.setter
def oracle_evaluation(self, value: bool) -> None:
""" set oracle evaluation """
self.data['oracle_evaluation'] = value

@staticmethod
def from_dict(a_dict: Dict) -> 'GroverResult':
""" create new object from a dictionary """
return GroverResult(a_dict)

def __getitem__(self, key: object) -> object:
if key == 'result':
warnings.warn('result deprecated, use assignment property.', DeprecationWarning)
return super().__getitem__('assignment')

return super().__getitem__(key)
11 changes: 7 additions & 4 deletions qiskit/aqua/algorithms/amplitude_estimators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@

""" Amplitude Estimators Package """

from .ae import AmplitudeEstimation
from .iqae import IterativeAmplitudeEstimation
from .mlae import MaximumLikelihoodAmplitudeEstimation
from .ae import AmplitudeEstimation, AmplitudeEstimationResult
from .iqae import IterativeAmplitudeEstimation, IterativeAmplitudeEstimationResult
from .mlae import MaximumLikelihoodAmplitudeEstimation, MaximumLikelihoodAmplitudeEstimationResult

__all__ = [
'AmplitudeEstimation',
'AmplitudeEstimationResult',
'IterativeAmplitudeEstimation',
'MaximumLikelihoodAmplitudeEstimation'
'IterativeAmplitudeEstimationResult',
'MaximumLikelihoodAmplitudeEstimation',
'MaximumLikelihoodAmplitudeEstimationResult'
]
157 changes: 154 additions & 3 deletions qiskit/aqua/algorithms/amplitude_estimators/ae.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from typing import Optional, Union, List, Tuple, Dict, Any
import logging
import warnings
from collections import OrderedDict
import numpy as np
from scipy.stats import chi2, norm
Expand All @@ -26,7 +27,7 @@
from qiskit.aqua.utils import CircuitFactory
from qiskit.aqua.circuits import PhaseEstimationCircuit
from qiskit.aqua.utils.validation import validate_min
from .ae_algorithm import AmplitudeEstimationAlgorithm
from .ae_algorithm import AmplitudeEstimationAlgorithm, AmplitudeEstimationAlgorithmResult
from .ae_utils import pdf_a, derivative_log_pdf_a, bisect_max

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -356,7 +357,7 @@ def loglikelihood(a):
self._ret['ml_value'] = a_opt
self._ret['mle'] = val_opt

def _run(self) -> dict:
def _run(self) -> 'AmplitudeEstimationResult':
# check if A factory has been set
if self.a_factory is None:
raise AquaError("a_factory must be set!")
Expand Down Expand Up @@ -444,4 +445,154 @@ def _run(self) -> dict:
kind = 'likelihood_ratio' # empirically the most precise kind
self._ret['95%_confidence_interval'] = self.confidence_interval(alpha, kind)

return self._ret
ae_result = AmplitudeEstimationAlgorithmResult()
ae_result.a_estimation = self._ret['value']
ae_result.estimation = self._ret['estimation']
ae_result.num_oracle_queries = self._ret['num_oracle_queries']
ae_result.confidence_interval = self._ret['95%_confidence_interval']

result = AmplitudeEstimationResult()
result.combine(ae_result)
result.ml_value = self._ret['ml_value']
result.mapped_a_samples = self._ret['values']
result.probabilities = self._ret['probabilities']
result.shots = self._ret['shots']
result.mle = self._ret['mle']
if 'statevector' in self._ret:
result.circuit_result = self._ret['statevector']
elif 'counts' in self._ret:
result.circuit_result = dict(self._ret['counts'])
result.a_samples = self._ret['a_items']
result.y_measurements = self._ret['y_items']
result.mapped_values = self._ret['mapped_values']
result.max_probability = self._ret['max_probability']
return result


class AmplitudeEstimationResult(AmplitudeEstimationAlgorithmResult):
""" AmplitudeEstimation Result."""

@property
def ml_value(self) -> float:
""" returns ml_value """
return self.get('ml_value')

@ml_value.setter
def ml_value(self, value: float) -> None:
""" set ml_value """
self.data['ml_value'] = value

@property
def mapped_a_samples(self) -> List[float]:
""" return mapped_a_samples """
return self.get('mapped_a_samples')

@mapped_a_samples.setter
def mapped_a_samples(self, value: List[float]) -> None:
""" set mapped_a_samples """
self.data['mapped_a_samples'] = value

@property
def probabilities(self) -> List[float]:
""" return probabilities """
return self.get('probabilities')

@probabilities.setter
def probabilities(self, value: List[float]) -> None:
""" set probabilities """
self.data['probabilities'] = value

@property
def shots(self) -> int:
""" return shots """
return self.get('shots')

@shots.setter
def shots(self, value: int) -> None:
""" set shots """
self.data['shots'] = value

@property
def mle(self) -> float:
""" return mle """
return self.get('mle')

@mle.setter
def mle(self, value: float) -> None:
""" set mle """
self.data['mle'] = value

@property
def circuit_result(self) -> Optional[Union[np.ndarray, Dict[str, int]]]:
""" return circuit result """
return self.get('circuit_result')

@circuit_result.setter
def circuit_result(self, value: Union[np.ndarray, Dict[str, int]]) -> None:
""" set circuit result """
self.data['circuit_result'] = value

@property
def a_samples(self) -> List[Tuple[float, float]]:
""" return a_samples """
return self.get('a_samples')

@a_samples.setter
def a_samples(self, value: List[Tuple[float, float]]) -> None:
""" set a_samples """
self.data['a_samples'] = value

@property
def y_measurements(self) -> List[Tuple[int, float]]:
""" return y_measurements """
return self.get('y_measurements')

@y_measurements.setter
def y_measurements(self, value: List[Tuple[int, float]]) -> None:
""" set y_measurements """
self.data['y_measurements'] = value

@property
def mapped_values(self) -> List[float]:
""" return mapped_values """
return self.get('mapped_values')

@mapped_values.setter
def mapped_values(self, value: List[float]) -> None:
""" set mapped_values """
self.data['mapped_values'] = value

@property
def max_probability(self) -> float:
""" return max_probability """
return self.get('max_probability')

@max_probability.setter
def max_probability(self, value: float) -> None:
""" set max_probability """
self.data['max_probability'] = value

@staticmethod
def from_dict(a_dict: Dict) -> 'AmplitudeEstimationResult':
""" create new object from a dictionary """
return AmplitudeEstimationResult(a_dict)

def __getitem__(self, key: object) -> object:
if key == 'statevector':
warnings.warn('statevector deprecated, use circuit_result property.',
DeprecationWarning)
return super().__getitem__('circuit_result')
elif key == 'counts':
warnings.warn('counts deprecated, use circuit_result property.', DeprecationWarning)
return super().__getitem__('circuit_result')
elif key == 'values':
warnings.warn('values deprecated, use mapped_a_samples property.', DeprecationWarning)
return super().__getitem__('mapped_a_samples')
elif key == 'y_items':
warnings.warn('y_items deprecated, use y_measurements property.', DeprecationWarning)
return super().__getitem__('y_measurements')
elif key == 'a_items':
warnings.warn('a_items deprecated, use a_samples property.', DeprecationWarning)
return super().__getitem__('a_samples')

return super().__getitem__(key)
Loading

0 comments on commit 2be89c1

Please sign in to comment.