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

Fix a bug in grover optimizer #1197

Merged
merged 14 commits into from
Aug 21, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions qiskit/optimization/algorithms/grover_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,23 @@
"""GroverOptimizer module"""

import logging
from typing import Optional, Dict, Union, List
import math
from copy import deepcopy
from typing import Optional, Dict, Union, List

import numpy as np

from qiskit import QuantumCircuit, QuantumRegister
from qiskit.circuit.library import QuadraticForm
from qiskit.providers import BaseBackend
from qiskit.aqua import QuantumInstance, aqua_globals
from qiskit.aqua.algorithms.amplitude_amplifiers.grover import Grover
from qiskit.aqua.components.initial_states import Custom
from qiskit.aqua.components.oracles import CustomCircuitOracle
from qiskit.circuit.library import QuadraticForm
from qiskit.providers import BaseBackend
from .optimization_algorithm import OptimizationAlgorithm, OptimizationResult
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo
from ..problems import Variable
from ..problems.quadratic_program import QuadraticProgram
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo


logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -152,6 +153,7 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:

# convert problem to QUBO
problem_ = self._qubo_converter.convert(problem)
problem_init = deepcopy(problem_)

# convert to minimization problem
sense = problem_.objective.sense
Expand Down Expand Up @@ -260,15 +262,16 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
opt_x = np.array([1 if s == '1' else 0 for s in ('{0:%sb}' % n_key).format(optimum_key)])

# Compute function value
fval = problem_.objective.evaluate(opt_x)
fval = problem_init.objective.evaluate(opt_x)
result = OptimizationResult(x=opt_x, fval=fval, variables=problem_.variables)

# cast binaries back to integers
result = self._qubo_converter.interpret(result)

return GroverOptimizationResult(x=result.x, fval=result.fval, variables=result.variables,
operation_counts=operation_count, n_input_qubits=n_key,
n_output_qubits=n_value)
n_output_qubits=n_value, intermediate_fval=fval,
threshold=threshold)

def _measure(self, circuit: QuantumCircuit) -> str:
"""Get probabilities from the given backend, and picks a random outcome."""
Expand Down Expand Up @@ -332,7 +335,7 @@ class GroverOptimizationResult(OptimizationResult):

def __init__(self, x: Union[List[float], np.ndarray], fval: float, variables: List[Variable],
operation_counts: Dict[int, Dict[str, int]], n_input_qubits: int,
n_output_qubits: int) -> None:
n_output_qubits: int, intermediate_fval: float, threshold: float) -> None:
"""
Constructs a result object with the specific Grover properties.

Expand All @@ -343,11 +346,16 @@ def __init__(self, x: Union[List[float], np.ndarray], fval: float, variables: Li
operation_counts: The counts of each operation performed per iteration.
n_input_qubits: The number of qubits used to represent the input.
n_output_qubits: The number of qubits used to represent the output.
intermediate_fval: The intermediate value of the objective function of the solution,
that is expected to be identical with ``fval``.
threshold: The threshold of Grover algorithm.
"""
super().__init__(x, fval, variables, None)
raw_results = {'intermediate_fval': fval, 'threshold': threshold}
t-imamichi marked this conversation as resolved.
Show resolved Hide resolved
super().__init__(x, fval, variables, raw_results)
self._operation_counts = operation_counts
self._n_input_qubits = n_input_qubits
self._n_output_qubits = n_output_qubits
self._intermediate_fval = intermediate_fval
t-imamichi marked this conversation as resolved.
Show resolved Hide resolved

@property
def operation_counts(self) -> Dict[int, Dict[str, int]]:
Expand Down
2 changes: 2 additions & 0 deletions test/optimization/test_grover_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def validate_results(self, problem, results):
# Validate results.
np.testing.assert_array_almost_equal(comp_result.x, results.x)
self.assertEqual(comp_result.fval, results.fval)
self.assertAlmostEqual(results.fval, results.raw_results['intermediate_fval'])

def test_qubo_gas_int_zero(self):
"""Test for when the answer is zero."""
Expand All @@ -60,6 +61,7 @@ def test_qubo_gas_int_zero(self):
results = gmf.solve(op)
np.testing.assert_array_almost_equal(results.x, [0, 0])
self.assertEqual(results.fval, 0.0)
self.assertAlmostEqual(results.fval, results.raw_results['intermediate_fval'])

def test_qubo_gas_int_simple(self):
"""Test for simple case, with 2 linear coeffs and no quadratic coeffs or constants."""
Expand Down