Spaces:
Running
Running
File size: 8,222 Bytes
227c43a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | """
IBM Quantum Cloud Integration Plugin
This module implements a robust Cirq → Qiskit conversion utility that handles
a broad set of common gates (including parameterized rotations) and measurements.
It then authenticates with IBM Quantum using qiskit-ibm-provider, transpiles the
converted circuit, submits the job to an IBM backend, and returns the results.
Provider Setup Guidance:
1. Create an IBM Quantum account and retrieve your API token.
2. Save your token by calling:
from qiskit_ibm_provider import IBMProvider
IBMProvider.save_account(token='MY_API_TOKEN')
(This stores your credentials in $HOME/.qiskit/qiskit-ibm.json.)
3. Alternatively, set the environment variable QISKIT_IBM_TOKEN.
4. Or, for a single session, pass the token when instantiating the provider.
Requirements:
- cirq
- qiskit
- qiskit-ibm-provider
- sympy
"""
import cirq
import sympy
from qiskit import transpile
from qiskit_ibm_provider import IBMProvider
#############################################
# Part 1: Robust Cirq to Qiskit Conversion #
#############################################
def _handle_rx(rads):
from qiskit.circuit.library import RXGate
if isinstance(rads, sympy.Basic):
from qiskit.circuit import Parameter
return RXGate(Parameter(str(rads)))
elif isinstance(rads, (float, int)):
return RXGate(rads)
else:
return RXGate(rads)
def _handle_ry(rads):
from qiskit.circuit.library import RYGate
if isinstance(rads, sympy.Basic):
from qiskit.circuit import Parameter
return RYGate(Parameter(str(rads)))
else:
return RYGate(rads)
def _handle_rz(rads):
from qiskit.circuit.library import RZGate
if isinstance(rads, sympy.Basic):
from qiskit.circuit import Parameter
return RZGate(Parameter(str(rads)))
else:
return RZGate(rads)
def cirq_to_qiskit(cirq_circuit: cirq.Circuit):
"""
Converts a Cirq circuit into a Qiskit QuantumCircuit.
Supports:
- Single-qubit gates: X, Y, Z, S, T, H, and parameterized rotations (Rx, Ry, Rz).
- Two-qubit gates: CNOT, CZ, SWAP.
- Measurements.
Symbolic parameters in Cirq become Qiskit Parameter objects.
Returns:
A Qiskit QuantumCircuit.
"""
# Collect and sort qubits
all_qubits = sorted(cirq_circuit.all_qubits(), key=lambda q: str(q))
num_qubits = len(all_qubits)
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
qreg = QuantumRegister(num_qubits, 'q')
creg = ClassicalRegister(num_qubits, 'c')
qc = QuantumCircuit(qreg, creg)
qubit_map = {q: i for i, q in enumerate(all_qubits)}
for moment in cirq_circuit:
for op in moment.operations:
gate = op.gate
qubits = op.qubits
# Handle measurement
if isinstance(gate, cirq.MeasurementGate):
for q in qubits:
idx = qubit_map[q]
qc.measure(qreg[idx], creg[idx])
# Single-qubit operations
elif len(qubits) == 1:
idx = qubit_map[qubits[0]]
if isinstance(gate, cirq.XPowGate) and gate.exponent == 1 and gate.global_shift == 0:
qc.x(qreg[idx])
elif isinstance(gate, cirq.YPowGate) and gate.exponent == 1 and gate.global_shift == 0:
qc.y(qreg[idx])
elif isinstance(gate, cirq.ZPowGate) and gate.exponent == 1 and gate.global_shift == 0:
qc.z(qreg[idx])
# For constant gates, compare directly
elif gate == cirq.S:
qc.s(qreg[idx])
elif gate == cirq.T:
qc.t(qreg[idx])
elif gate == cirq.H:
qc.h(qreg[idx])
# Parametric rotations
elif isinstance(gate, cirq.XPowGate) and gate.global_shift == 0:
angle = sympy.pi * gate.exponent
qc.append(_handle_rx(angle), [qreg[idx]])
elif isinstance(gate, cirq.YPowGate) and gate.global_shift == 0:
angle = sympy.pi * gate.exponent
qc.append(_handle_ry(angle), [qreg[idx]])
elif isinstance(gate, cirq.ZPowGate) and gate.global_shift == 0:
angle = sympy.pi * gate.exponent
qc.append(_handle_rz(angle), [qreg[idx]])
else:
continue
# Two-qubit operations
elif len(qubits) == 2:
idx0 = qubit_map[qubits[0]]
idx1 = qubit_map[qubits[1]]
if isinstance(gate, cirq.CNOT):
qc.cx(qreg[idx0], qreg[idx1])
elif isinstance(gate, cirq.CZ):
qc.cz(qreg[idx0], qreg[idx1])
elif isinstance(gate, cirq.SWAP):
qc.swap(qreg[idx0], qreg[idx1])
else:
continue
else:
continue
return qc
###########################################
# Part 2: IBM Quantum Integration #
###########################################
def authenticate_ibm(token: str = None):
"""
Authenticates with IBM Quantum using the provided token.
If token is None, attempts to load credentials from the environment or saved file.
Returns the IBMProvider instance.
"""
if token:
return IBMProvider(token=token)
else:
return IBMProvider()
def submit_cirq_to_ibm(cirq_circuit: cirq.Circuit, token: str = None, shots: int = 1024, backend_name: str = None):
"""
Converts a Cirq circuit to a Qiskit circuit, transpiles it for an IBM backend,
submits the job, and returns the job ID and results.
"""
provider = authenticate_ibm(token)
qiskit_circ = cirq_to_qiskit(cirq_circuit)
if qiskit_circ is None:
raise ValueError("Conversion from Cirq to Qiskit failed.")
if backend_name:
backend = provider.get_backend(backend_name)
else:
simulator_backends = provider.backends(filters=lambda b: b.configuration().simulator)
if not simulator_backends:
raise ValueError("No simulator backends available.")
from qiskit_ibm_provider import least_busy
backend = least_busy(simulator_backends)
transpiled_circ = transpile(qiskit_circ, backend=backend)
job = backend.run(transpiled_circ, shots=shots)
job_id = job.job_id()
result = job.result()
counts = result.get_counts()
return job_id, counts
def demo_hardware_integration_real(token: str, cirq_circuit: cirq.Circuit):
"""
Demonstrates real integration by converting a Cirq circuit to Qiskit,
submitting it to IBM Quantum, and returning job results.
"""
try:
job_id, counts = submit_cirq_to_ibm(cirq_circuit, token, shots=1024)
return {
"success": True,
"job_id": job_id,
"status": "Completed",
"results": counts
}
except Exception as e:
return {
"success": False,
"message": str(e)
}
if __name__ == "__main__":
# Example demonstration:
q0, q1 = cirq.LineQubit.range(2)
demo_circuit = cirq.Circuit(
cirq.H(q0),
cirq.CNOT(q0, q1),
cirq.measure(q0, key='m0'),
cirq.measure(q1, key='m1')
)
# Replace "YOUR_TOKEN_HERE" with your actual IBM Quantum API token.
token = "5930ef6e6c64d2c69651052ee317561b8f64a6ff614e051f8053eb8a3b813e864b7ac94e2d52f97ac487953419e7d62416379a99e0902a0a24b5842c8a2b9e16"
try:
job_id, counts = submit_cirq_to_ibm(demo_circuit, token, shots=1024)
print("IBM Quantum Job submitted successfully!")
print("Job ID:", job_id)
print("Counts:", counts)
except Exception as error:
print("Error during IBM Quantum integration:")
print(error) |