Superfermion logo
Guides

Framework Interop

Import and export circuits between Superfermion, Qiskit, Cirq, PennyLane, and OpenQASM 2/3.

Import/Export Matrix

DirectionQiskitCirqPennyLaneOpenQASM 2OpenQASM 3BraketIonQStim
Import → SFfrom_qiskitfrom_cirqfrom_pennylanefrom_qasmfrom_qasm3———
Export SF →to_qiskitto_cirqto_pennylaneto_qasmto_qasm3to_braketto_ionqto_stim

Qiskit

from superfermion.bridge import from_qiskit, to_qiskit
from qiskit import QuantumCircuit
import superfermion as sf

# Qiskit → Superfermion
qiskit_qc = QuantumCircuit(2)
qiskit_qc.h(0)
qiskit_qc.cx(0, 1)
sf_qc = from_qiskit(qiskit_qc)

# Superfermion → Qiskit
sf_qc = sf.Circuit(2).h(0).cnot(0, 1)
qiskit_qc = to_qiskit(sf_qc)

# Run on Qiskit Aer from Superfermion
from qiskit_aer import AerSimulator
qiskit_qc.measure_all()   # measurements so get_counts() has results
result = AerSimulator().run(qiskit_qc).result()
print(result.get_counts())

Stim

Export a Clifford circuit to Stim for fast tableau sampling and access to the detector / pymatching / sinter ecosystem. Non-Clifford gates raise ValueError.

from superfermion.bridge import to_stim
import superfermion as sf

qc = sf.Circuit(4).h(0)
for i in range(3):
    qc.cnot(i, i + 1)

stim_circuit, record_cbits = to_stim(qc)   # record_cbits: SF cbit per measurement
samples = stim_circuit.compile_sampler().sample(1000)

record_cbits[k] is the SF classical-bit index of the k-th measurement in Stim's record order (None if the measurement had no explicit cbit).

Cirq

from superfermion.bridge import from_cirq, to_cirq

# Cirq → Superfermion
import cirq
cirq_qc = cirq.Circuit(cirq.H(cirq.LineQubit(0)), cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(1)))
sf_qc = from_cirq(cirq_qc)

# Superfermion → Cirq
cirq_qc = to_cirq(sf_qc)

PennyLane

from superfermion.bridge import from_pennylane, to_pennylane
import pennylane as qml
import superfermion as sf

# PennyLane → Superfermion
dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
def circuit(x):
    qml.RY(x, wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.state()

# Extract the tape and convert
pl_tape = qml.workflow.construct_tape(circuit)(0.5)
sf_qc = from_pennylane(pl_tape)
print(sf.run(sf_qc.bind({"x": 0.5}), shots=100).counts)

# Superfermion → PennyLane (returns a quantum function for a QNode)
qfunc = to_pennylane(sf.Circuit(2).h(0).cnot(0, 1))

@qml.qnode(dev)
def pl_circuit():
    qfunc()
    return qml.state()

print(len(pl_circuit()))  # 4 amplitudes

OpenQASM 2.0

from superfermion.bridge import from_qasm, to_qasm

# Parse QASM (Rust-accelerated parser)
qasm_str = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
h q[0];
cx q[0], q[1];
"""
sf_qc = from_qasm(qasm_str)

# Export to QASM 2
qasm_output = to_qasm(sf_qc)

OpenQASM 3.0

# Export (built into Circuit)
qasm3_str = sf.Circuit(2).h(0).cnot(0, 1).to_qasm3()

# Import
from superfermion.serialization import from_qasm3
sf_qc = from_qasm3(qasm3_str)

AWS Braket

from superfermion.bridge import to_braket
import superfermion as sf

# Export Superfermion circuit to AWS Braket format
sf_qc = sf.Circuit(2).h(0).cnot(0, 1)
braket_circuit = to_braket(sf_qc)
print(type(braket_circuit).__name__)  # braket.circuits.Circuit

# Submit to AWS Braket (requires AWS credentials)
# from braket.aws import AwsDevice
# device = AwsDevice("arn:aws:braket:::device/quantum-simulator/amazon/sv1")
# device.run(braket_circuit, shots=1000)

IonQ

from superfermion.bridge import to_ionq

# Export to IonQ's native format
ionq_circuit = to_ionq(sf_qc)

JSON Round-Trip

# Serialize
json_str = sf.Circuit(2).h(0).cnot(0, 1).to_json()

# Deserialize
restored = sf.Circuit.from_json(json_str)
assert restored.gate_count == 2

Gate List Export

gates = sf.Circuit(2).h(0).cnot(0, 1).to_gate_list()
# [{"name": "H", "qubits": [0]}, {"name": "CNOT", "qubits": [0, 1]}]

# Rebuild from gate list (names are uppercase, lowercase the method name)
qc = sf.Circuit(2)
for g in gates:
    qc = getattr(qc, g["name"].lower())(*g.get("params", []), *g["qubits"])
print(qc.gate_count)  # 2

Caveats

  • Gate mappings are best-effort — framework-specific gates (e.g., PennyLane's qml.QubitUnitary) may not have a direct Superfermion equivalent
  • Parameter expressions — Qiskit's ParameterExpression is converted to symbolic parameters; complex expressions may be approximated
  • Classical control — OpenQASM 3's if/while statements are parsed but not executed; use Superfermion's Python API for classical logic

On this page