Skip to content

Commit ad6d91c

Browse files
Merge pull request #127 from Qiskit/master
fetch from origin
2 parents 3b7f27a + f826413 commit ad6d91c

16 files changed

+282
-234
lines changed

qiskit/optimization/algorithms/__init__.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,34 +28,43 @@
2828
:nosignatures:
2929
3030
OptimizationAlgorithm
31+
MultiStartOptimizer
3132
32-
Algorithms
33-
==========
33+
Algorithms and results
34+
======================
3435
3536
.. autosummary::
3637
:toctree: ../stubs/
3738
:nosignatures:
3839
40+
ADMMOptimizationResult
3941
ADMMOptimizer
42+
ADMMParameters
43+
ADMMState
4044
CobylaOptimizer
4145
CplexOptimizer
46+
GroverOptimizationRawResult
4247
GroverOptimizer
48+
MinimumEigenOptimizerResult
4349
MinimumEigenOptimizer
50+
OptimizationResult
51+
OptimizationResultStatus
4452
RecursiveMinimumEigenOptimizer
4553
SlsqpOptimizer
4654
4755
"""
4856

49-
from .optimization_algorithm import OptimizationResult
50-
from .optimization_algorithm import OptimizationAlgorithm
51-
from .admm_optimizer import ADMMOptimizer
52-
from .cplex_optimizer import CplexOptimizer
57+
from .admm_optimizer import ADMMOptimizer, ADMMOptimizationResult, ADMMState, ADMMParameters
5358
from .cobyla_optimizer import CobylaOptimizer
54-
from .minimum_eigen_optimizer import MinimumEigenOptimizer
59+
from .cplex_optimizer import CplexOptimizer
60+
from .grover_optimizer import GroverOptimizer, GroverOptimizationRawResult
61+
from .minimum_eigen_optimizer import MinimumEigenOptimizer, MinimumEigenOptimizerResult
62+
from .multistart_optimizer import MultiStartOptimizer
63+
from .optimization_algorithm import (OptimizationAlgorithm, OptimizationResult,
64+
OptimizationResultStatus)
5565
from .recursive_minimum_eigen_optimizer import RecursiveMinimumEigenOptimizer
56-
from .grover_optimizer import GroverOptimizer, GroverOptimizationResults
5766
from .slsqp_optimizer import SlsqpOptimizer
5867

5968
__all__ = ["ADMMOptimizer", "OptimizationAlgorithm", "OptimizationResult", "CplexOptimizer",
6069
"CobylaOptimizer", "MinimumEigenOptimizer", "RecursiveMinimumEigenOptimizer",
61-
"GroverOptimizer", "GroverOptimizationResults", "SlsqpOptimizer"]
70+
"GroverOptimizer", "GroverOptimizationRawResult", "SlsqpOptimizer"]

qiskit/optimization/algorithms/admm_optimizer.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import logging
1818
import time
1919
import warnings
20-
from typing import List, Optional, Any, Tuple, cast
20+
from typing import List, Optional, Tuple
2121

2222
import numpy as np
2323
from qiskit.aqua.algorithms import NumPyMinimumEigensolver
@@ -174,19 +174,21 @@ def __init__(self,
174174
class ADMMOptimizationResult(OptimizationResult):
175175
""" ADMMOptimization Result."""
176176

177-
def __init__(self, x: Optional[Any] = None, fval: Optional[Any] = None,
178-
state: Optional[ADMMState] = None, results: Optional[Any] = None,
179-
variables: Optional[List[Variable]] = None) -> None:
180-
super().__init__(x=x,
181-
variables=variables,
182-
fval=fval,
183-
results=results or state)
184-
self._state = state
177+
def __init__(self, x: np.ndarray, fval: float, variables: List[Variable],
178+
state: ADMMState) -> None:
179+
"""
180+
Args:
181+
x: the optimal value found by ADMM.
182+
fval: the optimal function value.
183+
variables: the list of variables of the optimization problem.
184+
state: the internal computation state of ADMM.
185+
"""
186+
super().__init__(x=x, fval=fval, variables=variables, raw_results=state)
185187

186188
@property
187-
def state(self) -> Optional[ADMMState]:
189+
def state(self) -> ADMMState:
188190
""" returns state """
189-
return self._state
191+
return self._raw_results
190192

191193

192194
class ADMMOptimizer(OptimizationAlgorithm):
@@ -277,6 +279,7 @@ def solve(self, problem: QuadraticProgram) -> ADMMOptimizationResult:
277279
# map integer variables to binary variables
278280
from ..converters.integer_to_binary import IntegerToBinary
279281
int2bin = IntegerToBinary()
282+
original_variables = problem.variables
280283
problem = int2bin.convert(problem)
281284

282285
# we deal with minimization in the optimizer, so turn the problem to minimization
@@ -363,16 +366,15 @@ def solve(self, problem: QuadraticProgram) -> ADMMOptimizationResult:
363366
# flip the objective sign again if required
364367
objective_value = objective_value * sense
365368

369+
# convert back integer to binary
370+
base_result = OptimizationResult(solution, objective_value, original_variables)
371+
base_result = int2bin.interpret(base_result)
372+
366373
# third parameter is our internal state of computations.
367-
result = ADMMOptimizationResult(x=solution,
368-
fval=objective_value,
369-
state=self._state,
370-
results={"integer_to_binary_converter": copy.deepcopy(
371-
int2bin)},
372-
variables=problem.variables)
374+
result = ADMMOptimizationResult(x=base_result.x, fval=base_result.fval,
375+
variables=base_result.variables,
376+
state=self._state)
373377

374-
# convert back integer to binary
375-
result = cast(ADMMOptimizationResult, int2bin.interpret(result))
376378
# debug
377379
self._log.debug("solution=%s, objective=%s at iteration=%s",
378380
solution, objective_value, iteration)

qiskit/optimization/algorithms/cobyla_optimizer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121

2222
from .multistart_optimizer import MultiStartOptimizer
2323
from .optimization_algorithm import OptimizationResult
24-
from ..problems.quadratic_program import QuadraticProgram
25-
from ..problems.constraint import Constraint
2624
from ..exceptions import QiskitOptimizationError
2725
from ..infinity import INFINITY
26+
from ..problems.constraint import Constraint
27+
from ..problems.quadratic_program import QuadraticProgram
2828

2929

3030
class CobylaOptimizer(MultiStartOptimizer):

qiskit/optimization/algorithms/cplex_optimizer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
"""The CPLEX optimizer wrapped to be used within Qiskit's optimization module."""
1717

18-
from typing import Optional
1918
import logging
19+
from typing import Optional
2020

2121
from .optimization_algorithm import OptimizationAlgorithm, OptimizationResult
2222
from ..exceptions import QiskitOptimizationError
@@ -136,9 +136,9 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
136136

137137
# create results
138138
result = OptimizationResult(x=sol.get_values(),
139-
variables=problem.variables,
140139
fval=sol.get_objective_value(),
141-
results=sol)
140+
variables=problem.variables,
141+
raw_results=sol)
142142

143143
# return solution
144144
return result

qiskit/optimization/algorithms/grover_optimizer.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,20 @@
1616

1717
import copy
1818
import logging
19-
from typing import Optional, Dict, Union, Tuple
2019
import math
20+
from typing import Optional, Dict, Union, Tuple
2121

2222
import numpy as np
23-
2423
from qiskit import QuantumCircuit
25-
from qiskit.providers import BaseBackend
2624
from qiskit.aqua import QuantumInstance, aqua_globals
2725
from qiskit.aqua.algorithms.amplitude_amplifiers.grover import Grover
26+
from qiskit.providers import BaseBackend
27+
2828
from .optimization_algorithm import OptimizationAlgorithm, OptimizationResult
29-
from ..problems.quadratic_program import QuadraticProgram
30-
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo
3129
from ..converters.quadratic_program_to_negative_value_oracle import \
3230
QuadraticProgramToNegativeValueOracle
33-
31+
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo
32+
from ..problems.quadratic_program import QuadraticProgram
3433

3534
logger = logging.getLogger(__name__)
3635

@@ -133,7 +132,7 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
133132
n_value = self._num_value_qubits
134133

135134
# Variables for tracking the solutions encountered.
136-
num_solutions = 2**n_key
135+
num_solutions = 2 ** n_key
137136
keys_measured = []
138137

139138
# Variables for result object.
@@ -143,7 +142,7 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
143142

144143
# Variables for stopping if we've hit the rotation max.
145144
rotations = 0
146-
max_rotations = int(np.ceil(100*np.pi/4))
145+
max_rotations = int(np.ceil(100 * np.pi / 4))
147146

148147
# Initialize oracle helper object.
149148
orig_constant = problem_.objective.constant
@@ -164,7 +163,7 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
164163
while not improvement_found:
165164
# Determine the number of rotations.
166165
loops_with_no_improvement += 1
167-
rotation_count = int(np.ceil(aqua_globals.random.uniform(0, m-1)))
166+
rotation_count = int(np.ceil(aqua_globals.random.uniform(0, m - 1)))
168167
rotations += rotation_count
169168

170169
# Apply Grover's Algorithm to find values below the threshold.
@@ -196,7 +195,7 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
196195
threshold = optimum_value
197196
else:
198197
# Using Durr and Hoyer method, increase m.
199-
m = int(np.ceil(min(m * 8/7, 2**(n_key / 2))))
198+
m = int(np.ceil(min(m * 8 / 7, 2 ** (n_key / 2))))
200199
logger.info('No Improvement. M: %s', m)
201200

202201
# Check if we've already seen this value.
@@ -225,16 +224,17 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult:
225224
opt_x = [1 if s == '1' else 0 for s in ('{0:%sb}' % n_key).format(optimum_key)]
226225

227226
# Build the results object.
228-
grover_results = GroverOptimizationResults(operation_count, n_key, n_value, func_dict)
227+
grover_results = GroverOptimizationRawResult(operation_count, n_key, n_value, func_dict)
229228
fval = solutions[optimum_key]
230229
if sense == problem_.objective.Sense.MAXIMIZE:
231230
fval = -fval
232-
result = OptimizationResult(x=opt_x, variables=problem.variables, fval=fval,
233-
results={"grover_results": grover_results,
234-
"qubo_converter": copy.deepcopy(self._qubo_converter),
235-
"negative_value_oracle_converter": copy.deepcopy(
236-
opt_prob_converter)
237-
})
231+
result = OptimizationResult(x=opt_x, fval=fval, variables=problem.variables,
232+
raw_results={"grover_results": grover_results,
233+
"qubo_converter": copy.deepcopy(
234+
self._qubo_converter),
235+
"negative_value_oracle_converter": copy.deepcopy(
236+
opt_prob_converter)
237+
})
238238

239239
# cast binaries back to integers
240240
result = self._qubo_converter.interpret(result)
@@ -247,7 +247,7 @@ def _measure(self, circuit: QuantumCircuit) -> str:
247247
freq = sorted(probs.items(), key=lambda x: x[1], reverse=True)
248248

249249
# Pick a random outcome.
250-
freq[len(freq)-1] = (freq[len(freq)-1][0], 1.0 - sum([x[1] for x in freq[0:len(freq)-1]]))
250+
freq[-1] = (freq[-1][0], 1.0 - sum(x[1] for x in freq[0:len(freq) - 1]))
251251
idx = aqua_globals.random.choice(len(freq), 1, p=[x[1] for x in freq])[0]
252252
logger.info('Frequencies: %s', freq)
253253

@@ -261,7 +261,7 @@ def _get_probs(self, qc: QuantumCircuit) -> Dict[str, float]:
261261
state = np.round(result.get_statevector(qc), 5)
262262
keys = [bin(i)[2::].rjust(int(np.log2(len(state))), '0')[::-1]
263263
for i in range(0, len(state))]
264-
probs = [np.round(abs(a)*abs(a), 5) for a in state]
264+
probs = [np.round(abs(a) * abs(a), 5) for a in state]
265265
hist = dict(zip(keys, probs))
266266
else:
267267
state = result.get_counts(qc)
@@ -276,13 +276,13 @@ def _get_probs(self, qc: QuantumCircuit) -> Dict[str, float]:
276276
@staticmethod
277277
def _twos_complement(v: int, n_bits: int) -> str:
278278
"""Converts an integer into a binary string of n bits using two's complement."""
279-
assert -2**n_bits <= v < 2**n_bits
279+
assert -2 ** n_bits <= v < 2 ** n_bits
280280

281281
if v < 0:
282-
v += 2**n_bits
282+
v += 2 ** n_bits
283283
bin_v = bin(v)[2:]
284284
else:
285-
format_string = '{0:0'+str(n_bits)+'b}'
285+
format_string = '{0:0' + str(n_bits) + 'b}'
286286
bin_v = format_string.format(v)
287287

288288
return bin_v
@@ -315,14 +315,14 @@ def _get_qubo_solutions(function_dict: Dict[Union[int, Tuple[int, int]], int], n
315315
constant = 0
316316
if -1 in function_dict:
317317
constant = function_dict[-1]
318-
format_string = '{0:0'+str(n_key)+'b}'
318+
format_string = '{0:0' + str(n_key) + 'b}'
319319

320320
# Iterate through every key combination.
321321
if print_solutions:
322322
print("QUBO Solutions:")
323323
print("==========================")
324324
solutions = {}
325-
for i in range(2**n_key):
325+
for i in range(2 ** n_key):
326326
solution = constant
327327

328328
# Convert int to a list of binary variables.
@@ -355,8 +355,8 @@ def _get_qubo_solutions(function_dict: Dict[Union[int, Tuple[int, int]], int], n
355355
return solutions
356356

357357

358-
class GroverOptimizationResults:
359-
"""A results object for Grover Optimization methods."""
358+
class GroverOptimizationRawResult:
359+
"""A raw result object for Grover Optimization methods."""
360360

361361
def __init__(self, operation_counts: Dict[int, Dict[str, int]],
362362
n_input_qubits: int, n_output_qubits: int,

0 commit comments

Comments
 (0)