qiskit-community / qiskit-optimization

Quantum Optimization
https://qiskit-community.github.io/qiskit-optimization/
Apache License 2.0
226 stars 139 forks source link

RecursiveMinimumEigenOptimizer with QAOA throws ValueError. #264

Closed lasys closed 2 years ago

lasys commented 2 years ago

Information

What is the current behavior?

RecursiveMinimumEigenOptimizer / pauli_trotter_evolution throws following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_2491547/4017197336.py in <module>
     31 
     32 # execute recursive qaoa
---> 33 RecursiveMinimumEigenOptimizer(MinimumEigenOptimizer(qaoa)).solve(max_cut_qubo)

~/.local/lib/python3.8/site-packages/qiskit_optimization/algorithms/recursive_minimum_eigen_optimizer.py in solve(self, problem)
    231 
    232             # solve current problem with optimizer
--> 233             res = self._optimizer.solve(problem_)  # type: OptimizationResult
    234             if self._history == IntermediateResult.ALL_ITERATIONS:
    235                 optimization_results.append(res)

~/.local/lib/python3.8/site-packages/qiskit_optimization/algorithms/minimum_eigen_optimizer.py in solve(self, problem)
    195         operator, offset = problem_.to_ising()
    196 
--> 197         return self._solve_internal(operator, offset, problem_, problem)
    198 
    199     def _solve_internal(

~/.local/lib/python3.8/site-packages/qiskit_optimization/algorithms/minimum_eigen_optimizer.py in _solve_internal(self, operator, offset, converted_problem, original_problem)
    208         if operator.num_qubits > 0:
    209             # approximate ground state of operator using min eigen solver
--> 210             eigen_result = self._min_eigen_solver.compute_minimum_eigenvalue(operator)
    211             # analyze results
    212             raw_samples = None

~/.local/lib/python3.8/site-packages/qiskit/algorithms/minimum_eigen_solvers/vqe.py in compute_minimum_eigenvalue(self, operator, aux_operators)
    449         # this sets the size of the ansatz, so it must be called before the initial point
    450         # validation
--> 451         self._check_operator_ansatz(operator)
    452 
    453         # set an expectation for this algorithm run (will be reset to None at the end)

~/.local/lib/python3.8/site-packages/qiskit/algorithms/minimum_eigen_solvers/qaoa.py in _check_operator_ansatz(self, operator)
    129         # Recreates a circuit based on operator parameter.
    130         if operator.num_qubits != self.ansatz.num_qubits:
--> 131             self.ansatz = QAOAAnsatz(
    132                 operator, self._reps, initial_state=self._initial_state, mixer_operator=self._mixer
    133             ).decompose()  # TODO remove decompose once #6674 is fixed

~/.local/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py in decompose(self)
   1290 
   1291         pass_ = Decompose()
-> 1292         decomposed_dag = pass_.run(circuit_to_dag(self))
   1293         return dag_to_circuit(decomposed_dag)
   1294 

~/.local/lib/python3.8/site-packages/qiskit/converters/circuit_to_dag.py in circuit_to_dag(circuit)
     53     dagcircuit.add_clbits(circuit.clbits)
     54 
---> 55     for register in circuit.qregs:
     56         dagcircuit.add_qreg(register)
     57 

~/.local/lib/python3.8/site-packages/qiskit/circuit/library/evolved_operator_ansatz.py in qregs(self)
    151         """A list of the quantum registers associated with the circuit."""
    152         if self._data is None:
--> 153             self._build()
    154         return self._qregs
    155 

~/.local/lib/python3.8/site-packages/qiskit/circuit/library/evolved_operator_ansatz.py in _build(self)
    202                         continue
    203 
--> 204                 evolved_op = self.evolution.convert((coeff * op).exp_i()).reduce()
    205                 circuits.append(evolved_op.to_circuit())
    206                 is_evolved_operator.append(True)  # has time coeff

~/.local/lib/python3.8/site-packages/qiskit/opflow/evolutions/pauli_trotter_evolution.py in convert(self, operator)
    101         #     # Sort into commuting groups
    102         #     operator = self._grouper.convert(operator).reduce()
--> 103         return self._recursive_convert(operator)
    104 
    105     def _recursive_convert(self, operator: OperatorBase) -> OperatorBase:

~/.local/lib/python3.8/site-packages/qiskit/opflow/evolutions/pauli_trotter_evolution.py in _recursive_convert(self, operator)
    145                 return circuit_no_identities
    146             elif isinstance(operator.primitive, PauliOp):
--> 147                 return self.evolution_for_pauli(operator.primitive)
    148             # Covers ListOp, ComposedOp, TensoredOp
    149             elif isinstance(operator.primitive, ListOp):

~/.local/lib/python3.8/site-packages/qiskit/opflow/evolutions/pauli_trotter_evolution.py in evolution_for_pauli(self, pauli_op)
    175         # to produce correct CoB circuit
    176         sig_bits = np.logical_or(pauli_op.primitive.z, pauli_op.primitive.x)
--> 177         a_sig_bit = int(max(np.extract(sig_bits, np.arange(pauli_op.num_qubits)[::-1])))
    178         destination = (I.tensorpower(a_sig_bit)) ^ (Z * pauli_op.coeff)
    179         cob = PauliBasisChange(destination_basis=destination, replacement_fn=replacement_fn)

ValueError: max() arg is an empty sequence

Steps to reproduce the problem

import networkx as nx
import numpy as np
from qiskit.algorithms.optimizers import SPSA
from qiskit.utils import QuantumInstance
from qiskit_optimization.algorithms import MinimumEigenOptimizer, RecursiveMinimumEigenOptimizer

from qiskit.algorithms import QAOA
from qiskit_optimization.applications import Maxcut
from qiskit import Aer
from qiskit_optimization.problems.quadratic_program import QuadraticProgram
from qiskit_optimization.converters import QuadraticProgramToQubo

# create graph
n = 4
graph = nx.Graph()
graph.add_nodes_from(np.arange(0, n, 1))
elist = [(0, 1, 1), (0, 3, 1), (0, 2, 1), (1, 2, 1), (1, 3, 1), (2, 3, 1)]
graph.add_weighted_edges_from(elist)

# create Maxcut
max_cut = Maxcut(graph)
max_cut_problem = max_cut.to_quadratic_program()
conv_toQubo = QuadraticProgramToQubo()
max_cut_qubo = conv_toQubo.convert(max_cut_problem)

# create qaoa
reps = 3
initial_point = [-0.54695145,  3.42723337] * reps 
quantum_instance = QuantumInstance(backend=Aer.get_backend('qasm_simulator'), shots=1024)
qaoa = QAOA(optimizer=SPSA(maxiter=0), reps=reps, initial_point=initial_point,  quantum_instance=quantum_instance)

# execute recursive qaoa
RecursiveMinimumEigenOptimizer(MinimumEigenOptimizer(qaoa)).solve(max_cut_qubo)

What is the expected behavior?

The program runs without errors.

Suggested solutions

None. It seems to be a sporadic error that does not always occur. I have tested the function using the same scheme with several graphs and I noticed that the error happens mainly with unweighted graphs.

t-imamichi commented 2 years ago

RecursiveMinimumEigenOptimizer iteratively solves the problem by fixing some variables. The subproblems have smaller number of variables than that of the original problem. So, setting initial_point explicitly does not work because the size of initial_point can be larger than that of subproblems.

This PR fixes the case where a subproblem is an identity. https://github.com/Qiskit/qiskit-terra/pull/7225

t-imamichi commented 2 years ago

If you still have an issue, please reopen this.