Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.26k stars 2.37k forks source link

Suprising behavior of BackendSampler with skip_transpilation=True #11627

Open nquetschlich opened 9 months ago

nquetschlich commented 9 months ago

Environment

What is happening?

Hi there,

I would like to run SamplingVQE with different ansatz circuits and compilation options to evaluate their performance for a FakeBackend. For that, I run something like

SamplingVQE(sampler=BackendSampler(FakeMontreal(), skip_transpilation=True), optimizer=COBYLA(maxiter=200), ansatz=ansatz_qc)

Here, I experienced that I could enter an ansatz_qc that has not been compiled to the used FakeBackend yet and still get a valid result when running compute_minimum_eigenvalue when using the skip_transpilation=True parameter.

In the example below, an QAOA ansatz is created for a sample MaxCut problem for an instance with four nodes.

How can we reproduce the issue?

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.primitives import BackendSampler
from qiskit.providers.fake_provider import FakeMontreal
from qiskit.algorithms.minimum_eigensolvers import SamplingVQE
from qiskit.algorithms.optimizers import COBYLA
import networkx as nx
import numpy as np
from qiskit_optimization.applications import Maxcut

def get_maxcut_instance():
    n = 4  
    G = nx.Graph()
    G.add_nodes_from(np.arange(0, n, 1))
    elist = [(0, 1, 1.0), (0, 2, 1.0), (0, 3, 1.0), (1, 2, 1.0), (2, 3, 1.0)]
    G.add_weighted_edges_from(elist)

    w = np.zeros([n, n])
    for i in range(n):
        for j in range(n):
            temp = G.get_edge_data(i, j, default=0)
            if temp != 0:
                w[i, j] = temp["weight"]
    return w

def get_maxcut_qubo(w):
    max_cut = Maxcut(w)
    qp = max_cut.to_quadratic_program()
    qubitOp, offset = qp.to_ising()
    return qubitOp, offset

def get_ansatz(maxcut) -> QuantumCircuit:
    qc = QuantumCircuit(4)
    qc.h(range(4))

    for i in range(4):
        for j in range(i + 1, 4):
            if maxcut[i][j]==1:
                p = Parameter("a")
                qc.rzz(p, i, j)

    m = Parameter("b")
    qc.rx(2 * m, range(4))

    qc.measure_all()
    return qc

maxcut = get_maxcut_instance()
ansatz = get_ansatz(maxcut)

qaoa = SamplingVQE(sampler=BackendSampler(FakeMontreal(), skip_transpilation=True), optimizer=COBYLA(maxiter=200), ansatz=ansatz)
qubitOp = get_maxcut_qubo(maxcut)[0]

res = qaoa.compute_minimum_eigenvalue(qubitOp)

What should happen?

I would have expected an assertion error that checks whether the to-be-executed ansatz_qc actually is transpiled according to the used backend. Am I overlooking something here? How is the underlying noise model of the FakeBackend considered when the quantum gates are not part of its basis gateset?

Any suggestions?

No response

nquetschlich commented 9 months ago

Update: I have played around a little more and would like to examine the effect different compilations have on the result quality. Therefore, I tried to execute the following:

from qiskit import transpile

ansatz_transpiled = transpile(ansatz, backend=FakeMontreal())

qaoa = SamplingVQE(sampler=BackendSampler(FakeMontreal(), skip_transpilation=True), optimizer=COBYLA(maxiter=200), ansatz=ansatz_transpiled)
qubitOp = get_maxcut_qubo(maxcut)[0]

res = qaoa.compute_minimum_eigenvalue(qubitOp)

Here, I get an AlgorithmError: 'The number of qubits of the ansatz does not match the operator, and the ansatz does not allow setting the number of qubits using num_qubits.'

Is there any way to circumvent this error while using already compiled ansatz circuits and skip the default transpilation?