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.06k stars 2.33k forks source link

Can't simulate circuits using SamplerV2. Error: "AttributeError: '_SingletonHGate' object has no attribute 'parameters'" #12391

Closed SrLo98 closed 4 months ago

SrLo98 commented 4 months ago

Environment

What is happening?

This issue is a continuation of the #12388. Basically, when I have a transpiled circuit and I want to simulate it using the library SamplerV2, it throws the error AttributeError: '_SingletonHGate' object has no attribute 'parameters' .

How can we reproduce the issue?

The code is the following one:

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler import InstructionProperties

# Import service
service = QiskitRuntimeService()
backend = service.get_backend('ibmq_qasm_simulator')

psi = [0.6269101568208251, 0.3990782681769692, 0.32708356008043044, 0.5837264221095967]
phi = [0.2134892935266178, -0.9769454035663946]

# Quantum Circuit
q0 = QuantumRegister(1, name = 'q0')
q1 = QuantumRegister(3, name = 'q1') 
c = ClassicalRegister(1, name = 'c')
qc = QuantumCircuit(q0,q1,c, name="qc")

# States initialization
psi_state = Gate('psi', 2, psi)
phi_state = Gate('phi', 1, phi)
qc.append(psi_state, q1[0:2])
qc.append(phi_state, q1[2:3])

# swap_test
qc.h(q0[0])
qc.cswap(q0[0], q1[0], q1[2])
qc.h(q0[0])
qc.measure(q0[0],c[0])

qc.draw(output="mpl")

And the output of the circuit: image

Then I added the instructions to the backend and transpiled the circuit:

service = QiskitRuntimeService()

backend = service.get_backend('ibmq_qasm_simulator')
backend.target.add_instruction(psi_state)
backend.target.add_instruction(phi_state)

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
qc_transpiled = pm.run(qc)

qc_transpiled.draw(output="mpl")

And the transpiled circuit look like this:

image

Nevertheless, when I try to run the circuit with SamplerV2, a new error appears:

shots = 2048
sampler = Sampler(backend=backend)
job = sampler.run(qc_transpiled, shots=shots)
job_result = job.result()
counts = job_result.get_counts()

The error is: AttributeError: 'RZGate' object has no attribute 'parameters'

The same happens if i choose pm = generate_preset_pass_manager(optimization_level=0, backend=backend) instead (this doesn't modify the initial circuit structure or gates). And now the error is similar but with another gate: AttributeError: '_SingletonHGate' object has no attribute 'parameters'

What should happen?

The Sampler object should be able to simulate the circuit.

Any suggestions?

No response

t-imamichi commented 4 months ago

Sampler.run call looks wrong. You should try job = sampler.run([qc_transpiled], shots=shots)

We have updated the error message #12031 and will be released as Qiskit 1.1 soon.

jakelishman commented 4 months ago

I'll close this as expected/solved, but feel free to reopen if there's more to discuss.

SrLo98 commented 4 months ago

Hello, by adding the instruction job = sampler.run([qc_transpiled], shots=shots) that problem was resolved. However, when I run the sampler and I try to get the job results doing:

shots = 2048
sampler = Sampler(backend=backend)
job = sampler.run(qc_transpiled, shots=shots)
job_result = job.result()
counts = job_result.get_counts()

A new error RuntimeJobFailureError: 'Unable to retrieve job result. Instruction psi on qubits (1, 2) from the 0-th circuit not is supported by the target. appears.

I tried to transpile the circuit by doing:

pm = generate_preset_pass_manager(optimization_level=0, backend=backend)
qc_transpiled = pm.run(qc)

And also including the target:

pm = generate_preset_pass_manager(optimization_level=0, backend=backend, target=backend.target)
qc_transpiled = pm.run(qc)

But in both cases the error persists. Thanks!

t-imamichi commented 4 months ago

You can add instructions to target. But, the resulting circuit does not work on a remote device because you cannot modify the target of the remote device. I suggest transpiling your circuit without modify target.

SrLo98 commented 4 months ago

You can add instructions to target. But, the resulting circuit does not work on a remote device because you cannot modify the target of the remote device. I suggest transpiling your circuit without modify target.

Thank you for responding, If I don't add any instruction and then I simply transpile the circuit, I got this error: TranspilerError: "HighLevelSynthesis was unable to synthesize Instruction(name='psi', num_qubits=2, num_clbits=0, params=[0.6269101568208251, 0.3990782681769692, 0.32708356008043044, 0.5837264221095967])."

The transpilation was done like this:

service = QiskitRuntimeService()
backend = service.get_backend('ibmq_qasm_simulator')

pm = generate_preset_pass_manager(optimization_level=0, backend=backend)
qc_transpiled = pm.run(qc)

Thank you

jakelishman commented 4 months ago

I suggest you look at the initialize or prepare_state methods to QuantumCircuit, which seems to be what you're trying to do.

At the moment you are defining some custom Gate without specifying anything about what that gate means. The transpiler is telling you that explicitly: "unable to synthesise [for the backend]", because it doesn't understand the gate you've given. If you want to make a one-off gate with a specific decomposition, you can make a circuit with only qubits and unitary operations and then call to_gate on it, or you can define a Gate subclass that specifies the definition field to be what you want. Alternatively, you can look in Qiskit's qiskit.circuit.library for pre-existing circuits/gates that might meet your needs.

SrLo98 commented 4 months ago

I suggest you look at the initialize or prepare_state methods to QuantumCircuit, which seems to be what you're trying to do.

At the moment you are defining some custom Gate without specifying anything about what that gate means. The transpiler is telling you that explicitly: "unable to synthesise [for the backend]", because it doesn't understand the gate you've given. If you want to make a one-off gate with a specific decomposition, you can make a circuit with only qubits and unitary operations and then call to_gate on it, or you can define a Gate subclass that specifies the definition field to be what you want. Alternatively, you can look in Qiskit's qiskit.circuit.library for pre-existing circuits/gates that might meet your needs.

Thank you for replying Jake,

Basically my program is using the SWAP routine to compute the inner product between two vectors A and B using amplitude encoding, using these states: $|Ψ⟩=\frac{1}{\sqrt{2}}[|0⟩⊗|A⟩+|1⟩⊗|B⟩]$ $|𝜑⟩=\frac{1}{\sqrt{Z}}[|A||0⟩-|B||1⟩]$ Where: $Z=|A|^2+|B|^2$

Just to create the issue, I just copied directly an example of previously computed values of both states for two random A and B vectors. As I commented in #12388, to do exactly the same with the functions transpile and assemble with older qiskit version, I had no problems.

I used instead initialize:

#States initialization
qc.initialize(psi, q1[0:2])
qc.initialize(phi, q1[2:3])

And then to simulate the circuit:

backend_QASM = Aer.get_backend('qasm_simulator')

# Number of realizations
    realizations = 2048

    # Create quantum circuit
    qc = build_QuantumCircuit_Amplitude(psi,phi)

    # Transpile the quantum circuit for the target backend
    qc_transpiled = transpile(qc, backend_QASM)

    # Assemble the transpiled quantum circuit into a Qobj
    qobj = assemble(qc_transpiled, shots=realizations)

    # Run the Qobj on the backend
    job = backend_QASM.run(qobj)

    # Get the result of the job
    job_result = job.result()

    # Get the counts from the result
    counts = job_result.get_counts()

But it's just now that I try to update the code to current Qiskit version that I'm struggling to make it work.

jakelishman commented 4 months ago

Your working examples don't appear to be much to do with new versions of Qiskit and more because you're simply using a different backend. The Runtime ibmq_qasm_simulator may not be reporting its ability to handle reset correctly.

Aer also provides Sampler implementations (in qiskit_aer.primitives), so you might just want to use one of those. If you want to continue using backend.run, you can get the Aer object from qiskit_aer.Aer, which is identical to the one you're using. There is no need to manually call assemble - that hasn't been necessary (or desirable) for at least a few years, and is mostly just an internal detail of how IBM services used to run. You should just pass the transpiled circuit directly to backend.run.