q-optimize/c3

Add support for `c3-toolset` gates in the `qiskit` interface

lazyoracle opened this issue · 0 comments

Describe the missing feature

There are quite a few gates used throughout the library which do not have a straightforward representation in native qiskit. This severely limits qiskit and c3-toolset interoperability. This pretty much means these gates can not be intuitively used when one accesses the c3-toolset simulator through the qiskit interface. This applies to gates like rx90p, rx90m, rxp, ry90p etc. These are defined as parametric gates in qiskit but there is non-existent very limited support for parametric gates in c3-toolset. So we need a qiskit compatible definition of these gates.

Ref:

GATES = {
"id": np.array([[1, 0], [0, 1]], dtype=np.complex128),
"rx90p": np.array([[1, -1j], [-1j, 1]], dtype=np.complex128) / np.sqrt(2),
"rx90m": np.array([[1, 1j], [1j, 1]], dtype=np.complex128) / np.sqrt(2),
"rxp": np.array([[0, -1j], [-1j, 0]], dtype=np.complex128),
"ry90p": np.array([[1, -1], [1, 1]], dtype=np.complex128) / np.sqrt(2),
"ry90m": np.array([[1, 1], [-1, 1]], dtype=np.complex128) / np.sqrt(2),
"ryp": np.array([[0, -1], [1, 0]], dtype=np.complex128),
"x": X,
"y": Y,
"rz90p": np.array([[1 - 1j, 0], [0, 1 + 1j]], dtype=np.complex128) / np.sqrt(2),
"rz90m": np.array([[1 + 1j, 0], [0, 1 - 1j]], dtype=np.complex128) / np.sqrt(2),
"rzp": np.array([[-1.0j, 0], [0, 1.0j]], dtype=np.complex128),
"crxp": np.array(
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, -1j, 0]],
dtype=np.complex128,
),
# What is the meaning of this gate?
"crzp": np.array(
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1j, 0], [0, 0, 0, 1j]], dtype=np.complex128
),
"cr": np.array(
[[0, -1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, 1j], [0, 0, 1j, 0]],
dtype=np.complex128,
),
"cr90": np.array(
[[1, -1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, 1j], [0, 0, 1j, 1]],
dtype=np.complex128,
)
/ np.sqrt(2),
"iswap": np.array(
[[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]], dtype=np.complex128
),
"cz": np.diag(np.array([1, 1, 1, -1], dtype=np.complex128)),
"ccz": np.diag(np.array([1, 1, 1, 1, 1, 1, 1, -1], dtype=np.complex128)),
"cx": np.array(
[[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=np.complex128
),
}

Describe the solution you'd like

A qiskit compatible gate library that allows one to easily use the gates mentioned above in qiskit circuits for simulations using both the c3-toolset and the qiskit simulator. These gates should be as much like native gates as possible, allowing for maximum usability in native qiskit circuits. This is usually achievable by making sure all the methods of Gate class work in the inherited custom gates. A new module like c3.qiskit.gates would make it convenient to use them in simulations.

from c3.qiskit.gates import RX90pGate as rx90p
from c3.qiskit.gates import CR90Gate as cr90
from c3.qiskit import C3Provider
from qiskit import Aer, execute, QuantumCircuit

c3_qiskit = C3Provider()
physics_backend = c3_qiskit.get_backend("c3_qasm_physics_simulator")
physics_backend.set_device_config("qiskit.cfg")
qiskit_backend = Aer.get_backend("qasm_simulator")

qc = QuantumCircuit(2, 2)
qc.append(rx90p, [0])
qc.append(cr90, [0, 1])

physics_sim = execute(qc, physics_backend)
print(f"C3 Physics Simulation: {physics_sim.result().get_counts()}")

qc.measure_all()
perfect_sim = execute(qc, qiskit_backend)
print(f"Qiskit Perfect Simulation: {perfect_sim.result().get_counts()}")

Describe alternatives you've considered

Using incorrect names for gates eg, in the examples/c3_qiskit.ipynb notebook

Additional context

Ref: Implementation of U Gate in qiskit.