Skip to content

Commit

Permalink
Fix a bug in grover optimizer (qiskit-community#1197)
Browse files Browse the repository at this point in the history
* fix a bug in grover optimizer

* add intermediate_fval and threshold to raw_results

* move intermediate_fval and threshold to properties

Co-authored-by: Manoel Marques <Manoel.Marques@ibm.com>
Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com>
  • Loading branch information
3 people authored and pbark committed Sep 16, 2020
1 parent 1bfc94e commit fcc8697
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
42 changes: 34 additions & 8 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)
self._operation_counts = operation_counts
self._n_input_qubits = n_input_qubits
self._n_output_qubits = n_output_qubits
self._intermediate_fval = intermediate_fval
self._threshold = threshold

@property
def operation_counts(self) -> Dict[int, Dict[str, int]]:
Expand Down Expand Up @@ -375,3 +383,21 @@ def n_output_qubits(self) -> int:
The number of qubits used to represent the output.
"""
return self._n_output_qubits

@property
def intermediate_fval(self) -> float:
"""Getter of the intermediate fval
Returns:
The intermediate value of fval before interpret.
"""
return self._intermediate_fval

@property
def threshold(self) -> float:
"""Getter of the threshold of Grover algorithm.
Returns:
The threshold of Grover algorithm.
"""
return self._threshold
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.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.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

0 comments on commit fcc8697

Please sign in to comment.