Appendix E: Framework Translation Dictionary

Side-by-side equivalents for Qiskit, Cirq, PennyLane, Q#, and Braket. Chapter 18 measured what gets lost in translation; this is the working reference.

⚠️ Read the endianness section first. It is the single most common source of silently wrong results when moving circuits between frameworks.


Endianness — read this first

Framework Convention |01⟩ means
Qiskit little-endian qubit 0 = 1, qubit 1 = 0
Cirq big-endian qubit 0 = 0, qubit 1 = 1
PennyLane big-endian qubit 0 = 0, qubit 1 = 1
Q# little-endian (LittleEndian type) explicit in the type system
OpenQASM little-endian matches Qiskit

Qiskit reverses relative to Cirq and PennyLane. A Bell state looks identical; a GHZ state with a single flipped qubit does not, and neither does any measured bitstring.

counts = {k[::-1]: v for k, v in counts.items()}    # Qiskit <-> Cirq bitstrings

Building a circuit

Qiskit

from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.h(0); qc.cx(0, 1); qc.measure_all()

Cirq

import cirq
q = cirq.LineQubit.range(2)
c = cirq.Circuit([cirq.H(q[0]), cirq.CNOT(q[0], q[1]), cirq.measure(*q, key="m")])

PennyLane

import pennylane as qml
dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
def circuit():
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.probs(wires=[0, 1])

Q#

operation Bell() : Result[] {
    use q = Qubit[2];
    H(q[0]);
    CNOT(q[0], q[1]);
    return [MResetZ(q[0]), MResetZ(q[1])];
}

Braket

from braket.circuits import Circuit
c = Circuit().h(0).cnot(0, 1)

Gate names

Gate Qiskit Cirq PennyLane Q# Braket OpenQASM
Hadamard h H Hadamard H h h
Pauli X x X PauliX X x x
Pauli Y y Y PauliY Y y y
Pauli Z z Z PauliZ Z z z
S s S S S s s
T t T T T t t
$R_x$ rx rx RX Rx rx rx
$R_y$ ry ry RY Ry ry ry
$R_z$ rz rz RZ Rz rz rz
Phase p Z**t PhaseShift R1 phaseshift p
CNOT cx CNOT CNOT CNOT cnot cx
CZ cz CZ CZ CZ cz cz
SWAP swap SWAP SWAP SWAP swap swap
Toffoli ccx TOFFOLI Toffoli CCNOT ccnot ccx
$\sqrt{X}$ sx X**0.5 SX v sx

⚠️ p vs rz is not the same gate. They differ by a global phase, which becomes relative and observable the moment either is controlled. Chapter 3 §3.6 measured this.

Execution

Task Qiskit Cirq PennyLane Braket
Simulator AerSimulator() cirq.Simulator() qml.device("default.qubit") LocalSimulator()
Run sim.run(qc, shots=N) sim.run(c, repetitions=N) call the QNode device.run(c, shots=N)
Counts .result().get_counts() .histogram(key="m") qml.counts() .result().measurement_counts
Statevector Statevector.from_instruction(qc) sim.simulate(c).final_state_vector qml.state() .result().values

Shots keyword differs: Qiskit shots=, Cirq repetitions=, PennyLane shots= on the device, Braket shots=.

Parameters

Qiskit Cirq PennyLane
Declare Parameter("θ") sympy.Symbol("θ") plain Python argument
Bind qc.assign_parameters({θ: 0.5}) cirq.ParamResolver({"θ": 0.5}) pass to the QNode
Sweep list comprehension cirq.Linspace("θ", 0, π, 10) array argument

PennyLane's model is different in kind: parameters are just function arguments, and gradients come from autodiff. That is the whole reason Part VI uses it.

⚠️ PennyLane gradients return shape (0,) unless parameters are pennylane.numpy arrays with requires_grad=True. Chapter 32 lost time to this.

Observables

Qiskit

from qiskit.quantum_info import SparsePauliOp
H = SparsePauliOp.from_list([("ZZ", 1.0), ("XI", 0.5)])

Cirq

H = cirq.Z(q[0]) * cirq.Z(q[1]) + 0.5 * cirq.X(q[0])

PennyLane

H = qml.Hamiltonian([1.0, 0.5], [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0)])

Qubit identity

  • Qiskit — integer indices into a register.
  • CirqLineQubit, GridQubit, NamedQubit; qubits are objects with device-relevant identity, which is why Cirq circuits carry topology naturally.
  • PennyLanewires, which may be integers or strings.
  • Q# — allocated in a use block, released automatically, and must be returned to $|0\rangle$.

Scheduling

Cirq's Moment has no Qiskit equivalent. A Cirq circuit is an explicit list of simultaneous operations; a Qiskit circuit is a list of instructions that the transpiler schedules. Converting Cirq → Qiskit loses the explicit timing, which Chapter 18 measured as the largest single translation loss.

What does not translate

Feature Notes
Cirq Moment structure Lost to Qiskit; recovered only by re-scheduling
Q# Adjoint / Controlled functors No equivalent; must be written out
PennyLane autodiff graph Circuit translates, differentiability does not
Braket verbatim boxes Provider-specific compilation control
Custom pulse calibrations Provider-specific, and qiskit.pulse was removed in 2.0
Mid-circuit measurement + feedforward Supported unevenly; check the target

OpenQASM as the bridge

from qiskit.qasm3 import dumps, loads
qasm = dumps(qc)
qc2 = loads(qasm)

Chapter 6 measured round-trip fidelity, and Chapter 18 measured where it fails: custom gates, pulse-level detail, and classical control flow are the lossy parts. For plain gate sequences it is reliable.


See also: Chapter 14 (Cirq), 15 (Q#), 16 (PennyLane), 17 (Braket), 18 (interoperability measured), Appendix F (OpenQASM).