C2QA / bosonic-qiskit

Extension of Qiskit to support hybrid boson-qubit simulations for the NQI C2QA effort.
BSD 2-Clause "Simplified" License
51 stars 14 forks source link

Serialization of `ParameterizedUnitaryGate`s #57

Closed teaguetomesh closed 1 year ago

teaguetomesh commented 2 years ago

Firstly - the changes made to resolve #39 have been working great - thank you!

I'm attempting to use Qiskit Runtime to simulate large bosonic-vqe circuits, and I have a working implementation (locally). I believe that it should also work remotely within Qiskit's Runtime - however, I am running into an issue when I attempt to submit a parameterized CVCircuit to the Runtime program. The issue appears to be occurring during the json serialization, and at some point ParameterizedUnitaryGate._define() is called and the code attempts to cast the unbound parameter as complex which results in the error.

Code to reproduce the error:

import json

import qiskit
from qiskit.circuit import ParameterVector
from qiskit.providers.ibmq.runtime.utils import RuntimeEncoder, RuntimeDecoder

import c2qa

qiskit_circuit = qiskit.QuantumCircuit(1)
param = qiskit.circuit.Parameter('theta')
qiskit_circuit.rx(param, qiskit_circuit.qubits[0])

#print(qc.draw())

# Serialize/deserialize circuit to demonstrate parameter re-ordering
qiskit_serial = json.dumps(qiskit_circuit, cls=RuntimeEncoder)
print('qiskit serialization is successful:')
print(qiskit_serial)

qumodes = c2qa.QumodeRegister(2)
bosonic_circuit = c2qa.CVCircuit(qumodes)

init_state = [0,2]
for i in range(qumodes.num_qumodes):
    bosonic_circuit.cv_initialize(init_state[i], qumodes[i])

phi = qiskit.circuit.Parameter('phi')
bosonic_circuit.cv_bs(phi, qumodes[0], qumodes[1])

#print(bosonic_circuit.draw())
print('\nAttempt to serialize an unbound CVCircuit:')
bosonic_serial = json.dumps(bosonic_circuit, cls=RuntimeEncoder)
print(bosonic_serial)

The weird part is that unbound Parameters are serializable in QuantumCircuits but not CVCircuits. I tried tracking down how Qiskit handles this and started with a RXGate. It looks like the unbound Parameter object is simply passed all the way through the definition.

I'm not sure if the same can be done for ParameterizedUnitaryGate because it inherits from UnitaryGate which doesn't take any parameters as input

CC @kevincsmith who I've been slacking about this issue

tjstavenger-pnnl commented 1 year ago

It's been quite some time since looking at this -- the ParameterizedUnitaryGate I made to allow us to parameterize CVCircuits is a bit of a workaround/hack to force Qiskit UnitaryGate to be parameterized. Out of the box, I don't believe Qiskit's UnitaryGate are parameterizable -- they need all parameter values to create their unitary matrices in _define(), which sounds like it needs to happen when serializing. The same problem has arised in #79 -- there the Qiskit Machine Learning package uses parameters that aren't bound during a transpile step where _define() is called.

If this is still needed, I can look to see if there's a way for us to custom serialize ParameterizedUnitaryGate to prevent it from calling _define().

tjstavenger-pnnl commented 1 year ago

@teaguetomesh -- The test case at https://github.com/C2QA/bosonic-qiskit/blob/main/tests/test_circuit.py#L130-L149 now passes after I added code to avoid the serialization error. I haven't tested the change any further than that. Are there ways you have availavle to test with the new changes?

tjstavenger-pnnl commented 1 year ago

With the test case provided passing, I'll close this ticket. If it is still a problem please do let us know.