Skip to content

Commit 599bcf6

Browse files
dongreenbergmanoelmarqueswoodsp-ibm
authored
* Add abelian property to opvecs and AbelianGrouper to operator init. * Break up PauliCoB big clifford synthesis function into smaller ones. * Add AbelianGrouper test. * Add better input checking in primitives and remove unnecessary print. * Fix coeffs bugs in pauli_cob.py. * Reorganize pauli_cob. All tests pass, with grouping on and off. * Change expectation_value backends to work through setters. * Reorganize local_simulator_sampler.py a bit to use it in a test. * Grouping Paulis works!! All tests pass. * Add "compute TPB pauli" function to pauli_cob. * Add WIP attempt at evolution over Abelian paulis. * Fix trotter bug. * Fix some other Trotter bugs. * Add parameters to OpPaulis and test. Parameterized evolution passes!!! * Add parameter binding for Op coefficients. * Add parameter binding, and binding tests. Tests pass. * Add division to Operators to make normalization convenient. * Finish merging MinEigenSolver PR. All tests pass. * Update QAOA, all tests pass!! * Update some QAOA imports and typehints. * Add QDrift trotterization method. All tests pass. * Start migrating QPE, tests fail. * fix spell * fix almost all style errors * fix copyright * fix import cycles, changed to relative imports when possible * relative imports * Add bind_params to state_fn_circuit.py and op_circuit.py, and tests. Add list unrolling for param binding, and tests. Tests pass. * Add param list handling for all Op types. * Make OpVec printing nicer. * Add op_converter to imports for better backwards compatibility. * Add AerPauliExpectation tests. Tests pass. Issue with Aer though. * Fix a few AerPauliExpectation bugs * Start building toward parameterized Qobj. * fix some lint errors * fix some lint errors * fix style * fix copyright * set style to defaults, fix aqua unit test loading * change loading tests qpe/iqpe * Fix OpPrimitive lint errors. * Fix operator_base.py lint errors. * Fix state_fn.py lint errors. * Fix OpVec lint errors. * Fix state_fn_circuit.py lint errors. * Fix state_fn_dict.py lint errors. * Fix state_fn_operator.py lint errors. * Fix state_fn_vector.py lint errors. Tests pass. * Fix QDrift test to deal with first Op in trotterization list being OpCircuit. * Fix op_circuit.py lint errors. * Fix op_pauli.py lint errors. * Fix op_composition.py lint errors. * Fix op_kron.py lint errors. * Fix abelian_grouper.py lint errors. Tests pass. * Fix pauli_cob.py lint errors. Tests pass. * Fix Expectation lint errors. Tests pass. * Fix circuit sampler lint errors. Tests pass. * Fix other expectation lint errors. Tests pass. * Fix trotterization lint errors. Tests pass. * Add MatrixEvolution shell, fix evolution lint errors. * Fix bug in evolution tests after fixing lint errors. * Fix cyclic import for lint. * fix pylint cyclic import error * Make tests pass. Add aux_ops back to VQE, and make VQE and QAOA take old or new ops. * fix spell and lint * Fix swapping issue in evolution. * Fix composition in OpEvolution. * Fix add OpSum and kron OpKron in OpEvolution. * Add to_opflow to legacy base_operator * Clean OpCircuit and StateFnCircuit __str__ * Fix qaoa mixer. * fix spell,style * Ok now really all tests pass. * add to_matrix_op() methods to ops. * Start migrating NumpyEigensolver for Opflow * Start removing back from op_primitive eval functions. All tests pass. * Update eval logic (to be able to remove back) for operator_combos. * Add to_matrix_op for OpMatrix and StateFnVector, and change some `if back`s to `if back is not None` * Finish decoupling back args from evals. All tests pass. * Remove back from eval logic. * Remove back from eval. All tests pass. * Change matrix_expectation.py to rely on to_matrix_op. * Migrate numpy_eigen_solver.py and numpy_minimum_eigen_solver. * Remove ToMatrixOp converter. * set VQE _auto_conversion to False for now * Add sampling and tests. Fix a rounding error in a test. Fix a not none error in numpy_eigen_solver.py. * Add array methods to OpVec. Fix typo in OpPauli. Allow reverse_endianness in to_opflow for WeightedPauli. * Make NumpyEigensolver return a StateFn in result.eigenstate. * Fix flaky optimization tests. Fix OpVec so iterator interface works. * Fix StateFnVector sampling. Fix sparse NumpyEigensolution. Fix some aux_op stuff. Fix some other things here and there. Please no more breakage. * Change some sparsity stuff. * fix spelling * Typehints. * More typehints * fix copyright * fix spelling * More typehints, make globals immutable. * fix style * Rearrange tests, Add CZ to globals. * Refactor some names. * Rename OpEvolution to EvolutionOp. Tests pass. * Rename primitive ops. All tests pass. * Finish renamings. * Test IBMQ Pauli expectation. All tests pass. * Update spelling. * Update Pauli to num_qubits. * Updating some naming. * Add diag support to fix knapsack issue. * fix unit test * fix unit test * fix travis * Turn half of Steve's comments. * Fix some exponentiation things. * Fix some exponentiation things. * Add trotterization_factory. All tests pass. * Add evolution_factory. All tests pass. * Add circuit_sampler_factory. All tests pass. * Rename get_primitives to primitive_strings. Turn some of Julien's changes. * Only allow sample_circuits to accept circuit_ops. Tests pass. * Turn more review changes * fix spell, style * Add matrix_op exp_i() into HamiltonianGate. Tests fail due to CircuitOp decompose() during composition. If commented out (line 158) tests pass. * Change CircuitOp and StateFnCircuit to rely on QuantumCircuit instead of Instruction. All tests pass. Add to_circuit_op to relevant ops. Solves all the decompose issues. * Add matrix_evolution and update QAOA to test matrix_op for cost operator. Add logic to update UCCSD to operator flow. Tests pass. * Delete PauliToInstruction, as it's obsolete. * Add to_pauli_op and tests. Tests pass. * Fix composed_op.py eval bug * Add sig digit rounding. VQE tests fail. * better precision for sig digit rounding. Tests pass. * Fix pep8, add comment * Add to_circuit_op to statefns, making DictToCircuit mostly obsolete. Tests pass. * fix cyclic imports * fix numpy boolean to string coercion * Update repr and a docstring. * Make ExpectationValues into converters. Test pass. * Fix bug from merge. * Fix bugs, make Minus just a CircuitStateFn and not a ComposedOp. * Uncomment HamiltonianGate * Update lots of docstrings part I. Tests pass. * fix docstring * More docstrings. Change class.rst so docs are generated for some python operator overloads. * Add navigation structure for docs to init files * More docs. * fix doctrings * 1) Change local_simulator_sampler.py to circuit_sampler.py 2) Set up circuit_samplers directory to be removed. 3) Add IBMQ VQE test. 4) Change AerPauliExpectation and CircuitSampler to handle expval_measurement/snapshots correctly. Tests pass. * 1) Delete circuit_samplers. 2) Allow CircuitSampler to attach_results. * Update Operator init * Change Operator directory names. Tests pass. * fix spell, docs * Turn Expectations purely into converters. Tests pass. * fix docs * skip IBMQ test * Add Converters docs. Tests pass. * fix spell * Add Evolutions docs. Tests pass. * Add Expectation docs. Tests pass. * fix spell * Add StateFn docs. Tests pass. * Fix typo. * Add ListOp init docs. * Fix some ordering * Little docs edits. * fix spell * Little docs edits. * 1) Add to_legacy_op to OperatorBase to allow non-migrated algos to accept new Operators. 2) Allow QPE and iQPE to accept new Operators, migrate tests. Tests pass. * Fix typehints for minimum_eigen_solvers * Make sure expectations can handle mixed observables. * fix spell * Turn some more of Steve's comments. Tests pass. * Turn some more of Steve's comments. Fix a buncha parameter stuff, and make sure mixed Pauli evolution works. * Turn some more of Steve's comments. Tests pass. * Turn some comments, fix a QAOA bug. * Try collapsing ListOp to_matrix a bit. * Turn more comments, fix some bugs. * Turn more comments, fix some bugs. * Update ListOp docs. * Update ListOp docs. * Update ListOp docs. * fix docstring * Update minimum_eigen_solvers setter typehints. * Add Changelog and tests for DictToCircuitSum. * Update VQE's construct_circuit and some changelog elements. * fix spell * Allow MinEigenOptimizer to accept StateFn result in result.eigenstate. * fix style * Update changelog with more detail. Update VQE to call super. * Typo Co-authored-by: Manoel Marques <manoel@us.ibm.com> Co-authored-by: woodsp <woodsp@us.ibm.com>
1 parent 0a59d4d commit 599bcf6

29 files changed

+1658
-419
lines changed

qiskit/aqua/algorithms/eigen_solvers/numpy_eigen_solver.py

+63-43
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""The Eigensolver algorithm."""
1616

17-
from typing import List, Optional
17+
from typing import List, Optional, Union
1818
import logging
1919
import pprint
2020
import warnings
@@ -23,15 +23,19 @@
2323

2424
from qiskit.aqua import AquaError
2525
from qiskit.aqua.algorithms import ClassicalAlgorithm
26-
from qiskit.aqua.operators import BaseOperator, op_converter
26+
from qiskit.aqua.operators import OperatorBase, LegacyBaseOperator, I, StateFn, ListOp
2727
from qiskit.aqua.utils.validation import validate_min
2828
from .eigen_solver_result import EigensolverResult
2929

3030
logger = logging.getLogger(__name__)
3131

3232

33+
# pylint: disable=invalid-name
34+
35+
3336
class NumPyEigensolver(ClassicalAlgorithm):
34-
r"""The NumPy Eigensolver algorithm.
37+
r"""
38+
The NumPy Eigensolver algorithm.
3539
3640
NumPy Eigensolver computes up to the first :math:`k` eigenvalues of a complex-valued square
3741
matrix of dimension :math:`n \times n`, with :math:`k \leq n`.
@@ -42,8 +46,12 @@ class NumPyEigensolver(ClassicalAlgorithm):
4246
operator size, mostly in terms of number of qubits it represents, gets larger.
4347
"""
4448

45-
def __init__(self, operator: Optional[BaseOperator] = None, k: int = 1,
46-
aux_operators: Optional[List[BaseOperator]] = None) -> None:
49+
def __init__(self,
50+
operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None,
51+
k: int = 1,
52+
aux_operators: Optional[List[Optional[Union[OperatorBase,
53+
LegacyBaseOperator]]]] = None
54+
) -> None:
4755
"""
4856
Args:
4957
operator: Operator instance. If None is supplied it must be provided later before
@@ -56,50 +64,52 @@ def __init__(self, operator: Optional[BaseOperator] = None, k: int = 1,
5664
validate_min('k', k, 1)
5765
super().__init__()
5866

59-
self._in_operator = None
60-
self._in_aux_operators = None
6167
self._operator = None
6268
self._aux_operators = None
6369
self._in_k = k
64-
self._k = k # pylint: disable=invalid-name
70+
self._k = k
6571

6672
self.operator = operator
6773
self.aux_operators = aux_operators
6874

6975
self._ret = {}
7076

7177
@property
72-
def operator(self) -> BaseOperator:
78+
def operator(self) -> Optional[OperatorBase]:
7379
""" returns operator """
74-
return self._in_operator
80+
return self._operator
7581

7682
@operator.setter
77-
def operator(self, operator: BaseOperator) -> None:
83+
def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None:
7884
""" set operator """
79-
self._in_operator = operator
85+
if isinstance(operator, LegacyBaseOperator):
86+
operator = operator.to_opflow()
8087
if operator is None:
8188
self._operator = None
8289
else:
83-
self._operator = op_converter.to_matrix_operator(operator)
90+
self._operator = operator
8491
self._check_set_k()
8592

8693
@property
87-
def aux_operators(self) -> List[BaseOperator]:
94+
def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]:
8895
""" returns aux operators """
89-
return self._in_aux_operators
96+
return self._aux_operators
9097

9198
@aux_operators.setter
92-
def aux_operators(self, aux_operators: List[BaseOperator]) -> None:
99+
def aux_operators(self,
100+
aux_operators: Optional[List[Optional[Union[OperatorBase,
101+
LegacyBaseOperator]]]]) -> None:
93102
""" set aux operators """
94-
self._in_aux_operators = aux_operators
95103
if aux_operators is None:
96104
self._aux_operators = []
97105
else:
98106
aux_operators = \
99107
[aux_operators] if not isinstance(aux_operators, list) else aux_operators
100-
self._aux_operators = \
101-
[op_converter.to_matrix_operator(aux_op) if aux_op is not None else None
102-
for aux_op in aux_operators]
108+
converted = [op.to_opflow() if op is not None else None for op in aux_operators]
109+
# Chemistry passes aux_ops with 0 qubits and paulis sometimes
110+
zero_op = I.tensorpower(self.operator.num_qubits) * 0.0
111+
converted = [zero_op if op == 0 else op for op in converted]
112+
self._aux_operators = converted
103113

104114
@property
105115
def k(self) -> int:
@@ -119,28 +129,30 @@ def supports_aux_operators(self) -> bool:
119129

120130
def _check_set_k(self):
121131
if self._operator is not None:
122-
if self._in_k > self._operator.matrix.shape[0]:
123-
self._k = self._operator.matrix.shape[0]
132+
if self._in_k > 2**(self._operator.num_qubits):
133+
self._k = 2**(self._operator.num_qubits)
124134
logger.debug("WARNING: Asked for %s eigenvalues but max possible is %s.",
125135
self._in_k, self._k)
126136
else:
127137
self._k = self._in_k
128138

129139
def _solve(self):
130-
if self._operator is None:
131-
raise ValueError('Operator is None but must be set!')
132-
if self._operator.dia_matrix is None:
133-
if self._k >= self._operator.matrix.shape[0] - 1:
134-
logger.debug("SciPy doesn't support to get all eigenvalues, using NumPy instead.")
135-
eigval, eigvec = np.linalg.eig(self._operator.matrix.toarray())
136-
else:
137-
eigval, eigvec = scisparse.linalg.eigs(self._operator.matrix, k=self._k, which='SR')
138-
else:
139-
eigval = np.sort(self._operator.matrix.data)[:self._k]
140-
temp = np.argsort(self._operator.matrix.data)[:self._k]
141-
eigvec = np.zeros((self._operator.matrix.shape[0], self._k))
140+
sp_mat = self._operator.to_spmatrix()
141+
# If matrix is diagonal, the elements on the diagonal are the eigenvalues. Solve by sorting.
142+
if scisparse.csr_matrix(sp_mat.diagonal()).nnz == sp_mat.nnz:
143+
diag = sp_mat.diagonal()
144+
eigval = np.sort(diag)[:self._k]
145+
temp = np.argsort(diag)[:self._k]
146+
eigvec = np.zeros((sp_mat.shape[0], self._k))
142147
for i, idx in enumerate(temp):
143148
eigvec[idx, i] = 1.0
149+
else:
150+
if self._k >= 2**(self._operator.num_qubits) - 1:
151+
logger.debug("SciPy doesn't support to get all eigenvalues, using NumPy instead.")
152+
eigval, eigvec = np.linalg.eig(self._operator.to_matrix())
153+
else:
154+
eigval, eigvec = scisparse.linalg.eigs(self._operator.to_spmatrix(),
155+
k=self._k, which='SR')
144156
if self._k > 1:
145157
idx = eigval.argsort()
146158
eigval = eigval[idx]
@@ -174,18 +186,24 @@ def _eval_aux_operators(self, wavefn, threshold=1e-12):
174186
values.append(None)
175187
continue
176188
value = 0.0
177-
if not operator.is_empty():
178-
value, _ = operator.evaluate_with_statevector(wavefn)
189+
if operator.coeff != 0:
190+
mat = operator.to_spmatrix()
191+
# Terra doesn't support sparse yet, so do the matmul directly if so
192+
# This is necessary for the particle_hole and other chemistry tests because the
193+
# pauli conversions are 2^12th large and will OOM error if not sparse.
194+
if isinstance(mat, scisparse.spmatrix):
195+
value = mat.dot(wavefn).dot(np.conj(wavefn))
196+
else:
197+
value = StateFn(operator, is_measurement=True).eval(wavefn)
179198
value = value.real if abs(value.real) > threshold else 0.0
180199
values.append((value, 0))
181200
return np.asarray(values)
182201

183202
def _run(self):
184-
"""Run the algorithm to compute up to the requested k number of eigenvalues.
185-
203+
"""
204+
Run the algorithm to compute up to the requested k number of eigenvalues.
186205
Returns:
187206
dict: Dictionary of results
188-
189207
Raises:
190208
AquaError: if no operator has been provided
191209
"""
@@ -203,7 +221,7 @@ def _run(self):
203221
if 'eigvals' in self._ret:
204222
result.eigenvalues = self._ret['eigvals']
205223
if 'eigvecs' in self._ret:
206-
result.eigenstates = self._ret['eigvecs']
224+
result.eigenstates = ListOp([StateFn(vec) for vec in self._ret['eigvecs']])
207225
if 'aux_ops' in self._ret:
208226
result.aux_operator_eigenvalues = self._ret['aux_ops']
209227

@@ -213,10 +231,12 @@ def _run(self):
213231

214232

215233
class ExactEigensolver(NumPyEigensolver):
216-
"""The deprecated Eigensolver algorithm."""
234+
"""
235+
The deprecated Eigensolver algorithm.
236+
"""
217237

218-
def __init__(self, operator: BaseOperator, k: int = 1,
219-
aux_operators: Optional[List[BaseOperator]] = None) -> None:
238+
def __init__(self, operator: LegacyBaseOperator, k: int = 1,
239+
aux_operators: Optional[List[LegacyBaseOperator]] = None) -> None:
220240
warnings.warn('Deprecated class {}, use {}.'.format('ExactEigensolver',
221241
'NumPyEigensolver'),
222242
DeprecationWarning)

qiskit/aqua/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313
# that they have been altered from the originals.
1414

1515
"""The Minimum Eigensolver interface"""
16+
1617
import warnings
1718
from abc import ABC, abstractmethod
1819
from typing import List, Optional, Union, Dict
1920

2021
import numpy as np
2122
from qiskit.aqua.algorithms import AlgorithmResult
22-
from qiskit.aqua.operators import BaseOperator
23+
from qiskit.aqua.operators import OperatorBase, LegacyBaseOperator
2324

2425

2526
class MinimumEigensolver(ABC):
@@ -33,8 +34,11 @@ class MinimumEigensolver(ABC):
3334

3435
@abstractmethod
3536
def compute_minimum_eigenvalue(
36-
self, operator: Optional[BaseOperator] = None,
37-
aux_operators: Optional[List[BaseOperator]] = None) -> 'MinimumEigensolverResult':
37+
self,
38+
operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None,
39+
aux_operators: Optional[List[Optional[Union[OperatorBase,
40+
LegacyBaseOperator]]]] = None
41+
) -> 'MinimumEigensolverResult':
3842
"""
3943
Computes minimum eigenvalue. Operator and aux_operators can be supplied here and
4044
if not None will override any already set into algorithm so it can be reused with
@@ -67,25 +71,27 @@ def supports_aux_operators(self) -> bool:
6771

6872
@property
6973
@abstractmethod
70-
def operator(self) -> BaseOperator:
74+
def operator(self) -> Optional[Union[OperatorBase, LegacyBaseOperator]]:
7175
""" returns operator """
7276
pass
7377

7478
@operator.setter
7579
@abstractmethod
76-
def operator(self, operator: BaseOperator) -> None:
80+
def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None:
7781
""" set operator """
7882
pass
7983

8084
@property
8185
@abstractmethod
82-
def aux_operators(self) -> List[BaseOperator]:
86+
def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]:
8387
""" returns aux operators """
8488
pass
8589

8690
@aux_operators.setter
8791
@abstractmethod
88-
def aux_operators(self, aux_operators: List[BaseOperator]) -> None:
92+
def aux_operators(self,
93+
aux_operators: Optional[List[Optional[Union[OperatorBase,
94+
LegacyBaseOperator]]]]) -> None:
8995
""" set aux operators """
9096
pass
9197

qiskit/aqua/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414

1515
"""The Numpy Minimum Eigensolver algorithm."""
1616

17-
from typing import List, Optional
17+
from typing import List, Optional, Union
1818
import logging
1919
import pprint
2020

2121
from qiskit.aqua.algorithms import ClassicalAlgorithm, NumPyEigensolver
22-
from qiskit.aqua.operators import BaseOperator
22+
from qiskit.aqua.operators import OperatorBase, LegacyBaseOperator
2323
from .minimum_eigen_solver import MinimumEigensolver, MinimumEigensolverResult
2424

2525
logger = logging.getLogger(__name__)
@@ -32,8 +32,11 @@ class NumPyMinimumEigensolver(ClassicalAlgorithm, MinimumEigensolver):
3232
The Numpy Minimum Eigensolver algorithm.
3333
"""
3434

35-
def __init__(self, operator: Optional[BaseOperator] = None,
36-
aux_operators: Optional[List[BaseOperator]] = None) -> None:
35+
def __init__(self,
36+
operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None,
37+
aux_operators: Optional[List[Optional[Union[OperatorBase,
38+
LegacyBaseOperator]]]] = None
39+
) -> None:
3740
"""
3841
Args:
3942
operator: Operator instance
@@ -43,27 +46,32 @@ def __init__(self, operator: Optional[BaseOperator] = None,
4346
self._ret = {} # TODO remove
4447

4548
@property
46-
def operator(self) -> BaseOperator:
49+
def operator(self) -> Optional[OperatorBase]:
4750
return self._ces.operator
4851

4952
@operator.setter
50-
def operator(self, operator: BaseOperator) -> None:
53+
def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None:
5154
self._ces.operator = operator
5255

5356
@property
54-
def aux_operators(self) -> List[BaseOperator]:
57+
def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]:
5558
return self._ces.aux_operators
5659

5760
@aux_operators.setter
58-
def aux_operators(self, aux_operators: List[BaseOperator]) -> None:
61+
def aux_operators(self,
62+
aux_operators: Optional[List[Optional[Union[OperatorBase,
63+
LegacyBaseOperator]]]]) -> None:
5964
self._ces.aux_operators = aux_operators
6065

6166
def supports_aux_operators(self) -> bool:
6267
return self._ces.supports_aux_operators()
6368

6469
def compute_minimum_eigenvalue(
65-
self, operator: BaseOperator = None,
66-
aux_operators: Optional[List[BaseOperator]] = None) -> MinimumEigensolverResult:
70+
self,
71+
operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None,
72+
aux_operators: Optional[List[Optional[Union[OperatorBase,
73+
LegacyBaseOperator]]]] = None
74+
) -> MinimumEigensolverResult:
6775
super().compute_minimum_eigenvalue(operator, aux_operators)
6876
return self._run()
6977

0 commit comments

Comments
 (0)