⚛️ Quantaflow Demo¶
Build quantum circuits once. Run them anywhere.
This notebook demonstrates the core features of Quantaflow — a framework-neutral quantum computing library by Northstar Corporation.
In [1]:
!pip install quantaflow -q
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/57.2 kB ? eta -:--:-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 57.2/57.2 kB 4.4 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.3/5.3 MB 57.7 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 935.6/935.6 kB 46.5 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.9/8.9 MB 94.7 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.4/12.4 MB 81.8 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.5/2.5 MB 82.6 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.2/2.2 MB 81.4 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 54.5/54.5 kB 4.2 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 167.9/167.9 kB 12.6 MB/s eta 0:00:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.8/8.8 MB 82.4 MB/s eta 0:00:00
1. Hello Quantum — Your First Circuit¶
In [2]:
from quantaflow import Circuit
from quantaflow.backends import PennyLaneBackend, QiskitBackend
# Build a Bell circuit: (|00⟩ + |11⟩) / √2
qc = Circuit(2)
qc.h(0) # Hadamard on qubit 0
qc.cx(0, 1) # CNOT: entangle qubits
qc.measure_all() # Measure all qubits
print(qc.draw())
q0: ─H────●────M─── q1: ──────X────M───
2. Run on Both Backends — Same Circuit, Zero Changes¶
In [3]:
# Run on PennyLane
pl_result = PennyLaneBackend().run(qc, shots=2000)
print("PennyLane:")
print(f" Counts: {pl_result.counts}")
print(f" Probabilities: { {k: round(v, 3) for k, v in pl_result.probabilities.items()} }")
print(f" Most common: {pl_result.most_common(1)}")
print()
# Run on Qiskit — exact same circuit
qi_result = QiskitBackend().run(qc, shots=2000)
print("Qiskit:")
print(f" Counts: {qi_result.counts}")
print(f" Probabilities: { {k: round(v, 3) for k, v in qi_result.probabilities.items()} }")
print(f" Most common: {qi_result.most_common(1)}")
/usr/local/lib/python3.12/dist-packages/pennylane/devices/device_api.py:201: PennyLaneDeprecationWarning: Setting shots on device is deprecated. Please use the `set_shots` transform on the respective QNode instead. warnings.warn(
PennyLane:
Counts: {'00': 1007, '01': 0, '10': 0, '11': 993}
Probabilities: {'00': 0.503, '01': 0.0, '10': 0.0, '11': 0.496}
Most common: [('00', 1007)]
Qiskit:
Counts: {'00': 1010, '11': 990}
Probabilities: {'00': 0.505, '11': 0.495}
Most common: [('00', 1010)]
3. Visualize Results¶
In [4]:
pl_result.plot_histogram(title="Bell State — PennyLane")
Out[4]:
In [5]:
qi_result.plot_probabilities(title="Bell State — Qiskit")
Out[5]:
4. Matplotlib Circuit Drawing¶
In [6]:
import math
fancy = Circuit(3)
fancy.h(0)
fancy.cx(0, 1)
fancy.ccx(0, 1, 2)
fancy.rx(0, math.pi / 4)
fancy.swap(1, 2)
fancy.crz(0, 1, math.pi / 2)
fancy.u3(2, 1.0, 2.0, 3.0)
fancy.measure_all()
print("ASCII:")
print(fancy.draw())
print(f"\nDepth: {fancy.depth} | Gates: {fancy.gate_count} | Ops: {fancy.count_ops()}")
ASCII:
q0: ─H────●────●────Rx(0.79)────────────●──────────────────────────────M───
q1: ──────X────●────────────────×────Rz(1.57)──────────────────────────M───
q2: ───────────X────────────────×────────────────U3(1.00,2.00,3.00)────M───
Depth: 5 | Gates: 7 | Ops: {'h': 1, 'cx': 1, 'ccx': 1, 'rx': 1, 'swap': 1, 'crz': 1, 'u3': 1}
In [7]:
fancy.draw('mpl')
Out[7]:
5. All 18 Gates in Action¶
In [8]:
import math
demo = Circuit(3)
# Pauli gates
demo.h(0).x(1).y(2).z(0)
# Phase gates
demo.s(0).t(1).sdg(0).tdg(1)
# Rotation gates
demo.rx(0, math.pi/4).ry(1, math.pi/3).rz(2, math.pi/6)
# Multi-qubit gates
demo.cx(0, 1).swap(1, 2).ccx(0, 1, 2)
# Controlled rotations
demo.crx(0, 1, 0.5).cry(1, 2, 0.7).crz(0, 2, 0.3)
# Universal gate
demo.u3(0, 1.0, 2.0, 3.0)
demo.measure_all()
print(f"Gates: {demo.gate_count}")
print(f"Ops breakdown: {demo.count_ops()}")
print(f"Depth: {demo.depth}")
result = PennyLaneBackend().run(demo, shots=1000)
print(f"\nTop 5 outcomes: {result.most_common(5)}")
result.plot_histogram(title="All 18 Gates Circuit")
Gates: 18
Ops breakdown: {'h': 1, 'x': 1, 'y': 1, 'z': 1, 's': 1, 't': 1, 'sdg': 1, 'tdg': 1, 'rx': 1, 'ry': 1, 'rz': 1, 'cx': 1, 'swap': 1, 'ccx': 1, 'crx': 1, 'cry': 1, 'crz': 1, 'u3': 1}
Depth: 10
Top 5 outcomes: [('110', 512), ('111', 374), ('010', 49), ('011', 34), ('101', 14)]
Out[8]:
6. Framework Interop — Drop Into Qiskit or PennyLane Anytime¶
In [9]:
# Build in Quantaflow
qc = Circuit(2)
qc.h(0).cx(0, 1).measure_all()
# Convert to Qiskit and use Qiskit's visualization
qiskit_qc = qc.to_qiskit()
print("Qiskit circuit:")
print(qiskit_qc.draw())
print(f"\nQiskit depth: {qiskit_qc.depth()}")
print(f"Qiskit gate count: {qiskit_qc.size()}")
Qiskit circuit:
┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1
Qiskit depth: 3
Qiskit gate count: 4
In [10]:
# Import a circuit FROM Qiskit
from qiskit import QuantumCircuit
# Build in pure Qiskit
qiskit_ghz = QuantumCircuit(3)
qiskit_ghz.h(0)
qiskit_ghz.cx(0, 1)
qiskit_ghz.cx(1, 2)
# Import into Quantaflow
ghz = Circuit.from_qiskit(qiskit_ghz)
ghz.measure_all()
print("Imported from Qiskit:")
print(ghz.draw())
# Run on PennyLane (!) — circuit came from Qiskit but runs anywhere
result = PennyLaneBackend().run(ghz, shots=1000)
print(f"\nGHZ state results: {result.counts}")
result.plot_histogram(title="GHZ State (built in Qiskit, ran on PennyLane)")
Imported from Qiskit:
q0: ─H────●─────────M───
q1: ──────X────●────M───
q2: ───────────X────M───
GHZ state results: {'000': 496, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 504}
Out[10]:
In [11]:
# Import from PennyLane
import pennylane as qml
with qml.tape.QuantumTape() as tape:
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
qml.Toffoli(wires=[0, 1, 2])
qf = Circuit.from_pennylane(tape)
qf.measure_all()
print("Imported from PennyLane:")
print(qf.draw())
# Run on Qiskit (!) — circuit came from PennyLane but runs anywhere
result = QiskitBackend().run(qf, shots=1000)
print(f"\nResults: {result.counts}")
Imported from PennyLane:
q0: ─H────●────●────M───
q1: ──────X────●────M───
q2: ───────────X────M───
Results: {'111': 491, '000': 509}
7. Circuit Manipulation¶
In [12]:
# Build a circuit
qc = Circuit(2)
qc.h(0).s(0).cx(0, 1)
print("Original:")
print(qc.draw())
# Get the inverse (adjoint)
inv = qc.inverse()
print("\nInverse (adjoint):")
print(inv.draw())
# Copy and modify
copy = qc.copy()
copy.t(1).measure_all()
print("\nCopy (modified):")
print(copy.draw())
print(f"\nOriginal has {len(qc)} gates, copy has {len(copy)} gates")
Original: q0: ─H────S────●─── q1: ───────────X─── Inverse (adjoint): q0: ─●────Sdg────H─── q1: ─X─────────────── Copy (modified): q0: ─H────S────●─────────M─── q1: ───────────X────T────M─── Original has 3 gates, copy has 4 gates
🚀 What's Next?¶
| Version | What's Coming |
|---|---|
| v0.0.3 | IBM Quantum hardware, Amazon Braket, noise models |
| v0.0.4 | VQE, QAOA algorithms, parameter sweeps |
| v0.0.5 | Transpiler, plugin system, benchmarking |
⭐ Star us on GitHub: github.com/NorthstarsIndustries/quantaflow
📦 PyPI: pypi.org/project/quantaflow