pythonibm-cloudquantum-computingcircuitqiskit

Issue running QAOA for Vertex Cover problem on IBM Quantum backend


I am trying to solve the Vertex Cover problem using QAOA on an IBM Quantum backend. I've successfully converted my graph into a QUBO formulation and then into an Ising Hamiltonian format. However, when I attempt to run my quantum circuit on the backend, it doesn't work as expected.

Here’s my code:

from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler, Session
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from qiskit_algorithms import QAOA
from qiskit_algorithms.optimizers import COBYLA
from qiskit_algorithms.utils import algorithm_globals

service = QiskitRuntimeService(channel="ibm_quantum", token="mytoken")
backend = service.backend("ibm_sherbrooke")

# QAOA configuration
algorithm_globals.random_seed = 123
sampler = Sampler(mode=backend)
qaoa = QAOA(sampler=sampler, optimizer=COBYLA(), reps=3)

# Use QAOA as the optimizer
optimizer = MinimumEigenOptimizer(qaoa)

# Solve the problem
result = optimizer.solve(qubo)

# Display results
print(result)

This the error message which I get after running the code:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[25], line 19
     16 optimizer = MinimumEigenOptimizer(qaoa)
     18 # Problem lösen
---> 19 result = optimizer.solve(qubo)
     21 # Ergebnisse anzeigen
     22 print(result)

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit_optimization\algorithms\minimum_eigen_optimizer.py:205, in MinimumEigenOptimizer.solve(self, problem)
    202 # construct operator and offset
    203 operator, offset = problem_.to_ising()
--> 205 return self._solve_internal(operator, offset, problem_, problem)

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit_optimization\algorithms\minimum_eigen_optimizer.py:218, in MinimumEigenOptimizer._solve_internal(self, operator, offset, converted_problem, original_problem)
    215 eigen_result: Optional[MinimumEigensolverResult] = None
    216 if operator.num_qubits > 0:
    217     # approximate ground state of operator using min eigen solver
--> 218     eigen_result = self._min_eigen_solver.compute_minimum_eigenvalue(operator)
    219     # analyze results
    220     raw_samples = None

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit_algorithms\minimum_eigensolvers\sampling_vqe.py:225, in SamplingVQE.compute_minimum_eigenvalue(self, operator, aux_operators)
    220 else:
    221     # we always want to submit as many estimations per job as possible for minimal
    222     # overhead on the hardware
    223     was_updated = _set_default_batchsize(self.optimizer)
--> 225     optimizer_result = self.optimizer.minimize(
    226         fun=evaluate_energy,  # type: ignore[arg-type]
    227         x0=initial_point,
    228         bounds=bounds,
    229     )
    231     # reset to original value
    232     if was_updated:

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit_algorithms\optimizers\scipy_optimizer.py:148, in SciPyOptimizer.minimize(self, fun, x0, jac, bounds)
    145     swapped_deprecated_args = True
    146     self._options["maxfun"] = self._options.pop("maxiter")
--> 148 raw_result = minimize(
    149     fun=fun,
    150     x0=x0,
    151     method=self._method,
    152     jac=jac,
    153     bounds=bounds,
    154     options=self._options,
    155     **self._kwargs,
    156 )
    157 if swapped_deprecated_args:
    158     self._options["maxiter"] = self._options.pop("maxfun")

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_minimize.py:737, in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    734     res = _minimize_tnc(fun, x0, args, jac, bounds, callback=callback,
    735                         **options)
    736 elif meth == 'cobyla':
--> 737     res = _minimize_cobyla(fun, x0, args, constraints, callback=callback,
    738                            bounds=bounds, **options)
    739 elif meth == 'cobyqa':
    740     res = _minimize_cobyqa(fun, x0, args, bounds, constraints, callback,
    741                            **options)

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_cobyla_py.py:35, in synchronized.<locals>.wrapper(*args, **kwargs)
     32 @functools.wraps(func)
     33 def wrapper(*args, **kwargs):
     34     with _module_lock:
---> 35         return func(*args, **kwargs)

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_cobyla_py.py:278, in _minimize_cobyla(fun, x0, args, constraints, rhobeg, tol, maxiter, disp, catol, callback, bounds, **unknown_options)
    275 def _jac(x, *args):
    276     return None
--> 278 sf = _prepare_scalar_function(fun, x0, args=args, jac=_jac)
    280 def calcfc(x, con):
    281     f = sf.fun(x)

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_optimize.py:288, in _prepare_scalar_function(fun, x0, jac, args, bounds, epsilon, finite_diff_rel_step, hess)
    284     bounds = (-np.inf, np.inf)
    286 # ScalarFunction caches. Reuse of fun(x) during grad
    287 # calculation reduces overall function evaluations.
--> 288 sf = ScalarFunction(fun, x0, args, grad, hess,
    289                     finite_diff_rel_step, bounds, epsilon=epsilon)
    291 return sf

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_differentiable_functions.py:222, in ScalarFunction.__init__(self, fun, x0, args, grad, hess, finite_diff_rel_step, finite_diff_bounds, epsilon)
    219     finite_diff_options["as_linear_operator"] = True
    221 # Initial function evaluation
--> 222 self._update_fun()
    224 # Initial gradient evaluation
    225 self._wrapped_grad, self._ngev = _wrapper_grad(
    226     grad,
    227     fun=self._wrapped_fun,
    228     args=args,
    229     finite_diff_options=finite_diff_options
    230 )

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_differentiable_functions.py:294, in ScalarFunction._update_fun(self)
    292 def _update_fun(self):
    293     if not self.f_updated:
--> 294         fx = self._wrapped_fun(self.x)
    295         if fx < self._lowest_f:
    296             self._lowest_x = self.x

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\scipy\optimize\_differentiable_functions.py:20, in _wrapper_fun.<locals>.wrapped(x)
     16 ncalls[0] += 1
     17 # Send a copy because the user may overwrite it.
     18 # Overwriting results in undefined behaviour because
     19 # fun(self.x) will change self.x, with the two no longer linked.
---> 20 fx = fun(np.copy(x), *args)
     21 # Make sure the function returns a true scalar
     22 if not np.isscalar(fx):

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit_algorithms\minimum_eigensolvers\sampling_vqe.py:320, in SamplingVQE._get_evaluate_energy.<locals>.evaluate_energy(parameters)
    315 parameters = np.reshape(parameters, (-1, num_parameters)).tolist()
    316 batch_size = len(parameters)
    318 estimator_result = estimator.run(
    319     batch_size * [ansatz], batch_size * [operator], parameters
--> 320 ).result()
    321 values = estimator_result.values
    323 if self.callback is not None:

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit\primitives\primitive_job.py:51, in PrimitiveJob.result(self)
     49 def result(self) -> ResultT:
     50     self._check_submitted()
---> 51     return self._future.result()

File ~\AppData\Local\Programs\Python\Python312\Lib\concurrent\futures\_base.py:449, in Future.result(self, timeout)
    447     raise CancelledError()
    448 elif self._state == FINISHED:
--> 449     return self.__get_result()
    451 self._condition.wait(timeout)
    453 if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:

File ~\AppData\Local\Programs\Python\Python312\Lib\concurrent\futures\_base.py:401, in Future.__get_result(self)
    399 if self._exception:
    400     try:
--> 401         raise self._exception
    402     finally:
    403         # Break a reference cycle with the exception in self._exception
    404         self = None

File ~\AppData\Local\Programs\Python\Python312\Lib\concurrent\futures\thread.py:58, in _WorkItem.run(self)
     55     return
     57 try:
---> 58     result = self.fn(*self.args, **self.kwargs)
     59 except BaseException as exc:
     60     self.future.set_exception(exc)

File f:\QuantumComputingProjects\IBM_Qiskit\Lib\site-packages\qiskit_algorithms\minimum_eigensolvers\diagonal_estimator.py:117, in _DiagonalEstimator._call(self, circuits, observables, parameter_values, **run_options)
    110 def _call(
    111     self,
    112     circuits: Sequence[int],
   (...)
    115     **run_options,
    116 ) -> _DiagonalEstimatorResult:
--> 117     job = self.sampler.run(
    118         [self._circuits[i] for i in circuits],
    119         parameter_values,
    120         **run_options,
    121     )
    122     sampler_result = job.result()
    123     samples = sampler_result.quasi_dists

TypeError: SamplerV2.run() takes 2 positional arguments but 3 were given

I have a few questions:

  1. Is the way I am using Sampler and QAOA correct for running on the IBM backend?
  2. Are there any specific steps I need to follow to ensure the quantum circuit runs correctly on ibm_sherbrooke?

Any help would be greatly appreciated!


Solution

  • Qiskit Optimization does not support the V2 versions of the primitives that are now needed to run on real devices (IBM backends). There is an open issue for that https://github.com/qiskit-community/qiskit-optimization/issues/587 though there some work is in progress, which you can see in the Pull Requests on the repository. Same for Qiskit Algorithms that the released version of Qiskit Optimization depends on.