Skip to content

Commit fba65c0

Browse files
t-imamichimanoelmarqueswoodsp-ibm
authored andcommitted
Fix a bug in grover optimizer (qiskit-community#1197)
* 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 <[email protected]> Co-authored-by: Steve Wood <[email protected]>
1 parent 52f0072 commit fba65c0

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

qiskit/optimization/algorithms/grover_optimizer.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,23 @@
1515
"""GroverOptimizer module"""
1616

1717
import logging
18-
from typing import Optional, Dict, Union, List
1918
import math
19+
from copy import deepcopy
20+
from typing import Optional, Dict, Union, List
2021

2122
import numpy as np
23+
2224
from qiskit import QuantumCircuit, QuantumRegister
23-
from qiskit.circuit.library import QuadraticForm
24-
from qiskit.providers import BaseBackend
2525
from qiskit.aqua import QuantumInstance, aqua_globals
2626
from qiskit.aqua.algorithms.amplitude_amplifiers.grover import Grover
2727
from qiskit.aqua.components.initial_states import Custom
2828
from qiskit.aqua.components.oracles import CustomCircuitOracle
29+
from qiskit.circuit.library import QuadraticForm
30+
from qiskit.providers import BaseBackend
2931
from .optimization_algorithm import OptimizationAlgorithm, OptimizationResult
32+
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo
3033
from ..problems import Variable
3134
from ..problems.quadratic_program import QuadraticProgram
32-
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo
33-
3435

3536
logger = logging.getLogger(__name__)
3637

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

153154
# convert problem to QUBO
154155
problem_ = self._qubo_converter.convert(problem)
156+
problem_init = deepcopy(problem_)
155157

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

262264
# Compute function value
263-
fval = problem_.objective.evaluate(opt_x)
265+
fval = problem_init.objective.evaluate(opt_x)
264266
result = OptimizationResult(x=opt_x, fval=fval, variables=problem_.variables)
265267

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

269271
return GroverOptimizationResult(x=result.x, fval=result.fval, variables=result.variables,
270272
operation_counts=operation_count, n_input_qubits=n_key,
271-
n_output_qubits=n_value)
273+
n_output_qubits=n_value, intermediate_fval=fval,
274+
threshold=threshold)
272275

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

333336
def __init__(self, x: Union[List[float], np.ndarray], fval: float, variables: List[Variable],
334337
operation_counts: Dict[int, Dict[str, int]], n_input_qubits: int,
335-
n_output_qubits: int) -> None:
338+
n_output_qubits: int, intermediate_fval: float, threshold: float) -> None:
336339
"""
337340
Constructs a result object with the specific Grover properties.
338341
@@ -343,11 +346,16 @@ def __init__(self, x: Union[List[float], np.ndarray], fval: float, variables: Li
343346
operation_counts: The counts of each operation performed per iteration.
344347
n_input_qubits: The number of qubits used to represent the input.
345348
n_output_qubits: The number of qubits used to represent the output.
349+
intermediate_fval: The intermediate value of the objective function of the solution,
350+
that is expected to be identical with ``fval``.
351+
threshold: The threshold of Grover algorithm.
346352
"""
347353
super().__init__(x, fval, variables, None)
348354
self._operation_counts = operation_counts
349355
self._n_input_qubits = n_input_qubits
350356
self._n_output_qubits = n_output_qubits
357+
self._intermediate_fval = intermediate_fval
358+
self._threshold = threshold
351359

352360
@property
353361
def operation_counts(self) -> Dict[int, Dict[str, int]]:
@@ -375,3 +383,21 @@ def n_output_qubits(self) -> int:
375383
The number of qubits used to represent the output.
376384
"""
377385
return self._n_output_qubits
386+
387+
@property
388+
def intermediate_fval(self) -> float:
389+
"""Getter of the intermediate fval
390+
391+
Returns:
392+
The intermediate value of fval before interpret.
393+
"""
394+
return self._intermediate_fval
395+
396+
@property
397+
def threshold(self) -> float:
398+
"""Getter of the threshold of Grover algorithm.
399+
400+
Returns:
401+
The threshold of Grover algorithm.
402+
"""
403+
return self._threshold

test/optimization/test_grover_optimizer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def validate_results(self, problem, results):
4343
# Validate results.
4444
np.testing.assert_array_almost_equal(comp_result.x, results.x)
4545
self.assertEqual(comp_result.fval, results.fval)
46+
self.assertAlmostEqual(results.fval, results.intermediate_fval)
4647

4748
def test_qubo_gas_int_zero(self):
4849
"""Test for when the answer is zero."""
@@ -60,6 +61,7 @@ def test_qubo_gas_int_zero(self):
6061
results = gmf.solve(op)
6162
np.testing.assert_array_almost_equal(results.x, [0, 0])
6263
self.assertEqual(results.fval, 0.0)
64+
self.assertAlmostEqual(results.fval, results.intermediate_fval)
6365

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

0 commit comments

Comments
 (0)