There's a real question when starting a quantum computing project: should you write circuits directly in Qiskit, or use HLQuantum's abstraction layer on top? Both are valid choices, and the right answer depends on what you're building.
This post gives you a concrete, code-driven comparison to help you decide.
The Core Difference
Qiskit is IBM's quantum SDK. It gives you direct, precise control over every gate, qubit, measurement, and compilation step. It targets IBM hardware natively and has the deepest ecosystem for IBM-specific workflows.
HLQuantum is a unified API that sits above Qiskit, Cirq, PennyLane, Braket, CUDA-Q, and IonQ. You write one circuit; it translates and dispatches to whichever backend you point it at. It trades some low-level control for portability and simplicity.
Side-by-Side: Bell State
Raw Qiskit:
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
sim = AerSimulator()
result = sim.run(qc, shots=1000).result()
print(result.get_counts()) # {'00': 501, '11': 499}
HLQuantum:
import hlquantum as hlq
qc = hlq.Circuit(2)
qc.h(0).cx(0, 1).measure_all()
result = hlq.run(qc, backend='qiskit', shots=1000)
print(result.counts) # {'00': 501, '11': 499}
About the same verbosity for a single backend. The difference shows up when you add more backends.
Side-by-Side: Running on Multiple Backends
Raw Qiskit (to add a second backend, you rewrite):
# Qiskit Aer
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc_qiskit = QuantumCircuit(2, 2)
qc_qiskit.h(0); qc_qiskit.cx(0, 1); qc_qiskit.measure_all()
result_qiskit = AerSimulator().run(qc_qiskit, shots=1000).result()
# PennyLane — completely different API, rewrite circuit
import pennylane as qml
dev = qml.device('default.qubit', wires=2)
@qml.qnode(dev)
def bell():
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return qml.probs(wires=[0, 1])
result_pennylane = bell()
# CUDA-Q — yet another API, rewrite again
import cudaq
@cudaq.kernel
def bell():
qvec = cudaq.qvector(2)
h(qvec[0]); cx(qvec[0], qvec[1]); mz(qvec)
result_cudaq = cudaq.sample(bell, shots_count=1000)
HLQuantum (one circuit, any backend):
import hlquantum as hlq
qc = hlq.Circuit(2)
qc.h(0).cx(0, 1).measure_all()
# Switch backends with one word
result_qiskit = hlq.run(qc, backend='qiskit')
result_pennylane = hlq.run(qc, backend='pennylane')
result_cudaq = hlq.run(qc, backend='cudaq') # GPU
result_cirq = hlq.run(qc, backend='cirq')
result_ionq = hlq.run(qc, backend='ionq', device='aria-1')
result_ibm = hlq.run(qc, backend='qiskit', device='ibm_sherbrooke')
This is where HLQuantum pays off — prototyping on a local simulator and deploying to QPU without rewriting the circuit.
Side-by-Side: VQE
Raw Qiskit VQE:
from qiskit_nature.second_q.drivers import PySCFDriver
from qiskit_nature.second_q.mappers import JordanWignerMapper
from qiskit_nature.second_q.circuit.library import UCCSD
from qiskit_algorithms import VQE
from qiskit_algorithms.optimizers import COBYLA
from qiskit.primitives import Estimator
driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735')
problem = driver.run()
mapper = JordanWignerMapper()
hamiltonian = mapper.map(problem.second_q_ops()[0])
ansatz = UCCSD(
problem.num_spatial_orbitals,
problem.num_particles,
mapper,
initial_state=problem.reference_state,
)
vqe = VQE(Estimator(), ansatz, COBYLA())
result = vqe.compute_minimum_eigenvalue(hamiltonian)
print(f"H2 ground state: {result.eigenvalue.real:.4f} Ha")
HLQuantum VQE:
import hlquantum as hlq
result = hlq.algorithms.vqe(
molecule='H2',
basis='sto-3g',
backend='qiskit',
optimizer='COBYLA',
)
print(f"H2 ground state: {result.energy:.4f} Ha")
# Switch to GPU:
result_gpu = hlq.algorithms.vqe(molecule='H2', backend='cudaq')
Raw Qiskit gives you full control over the ansatz, mapper, and driver. HLQuantum's one-liner is best for comparing backends or getting results quickly; raw Qiskit is better when you need custom ansatze or algorithm tuning.
When to Use Raw Qiskit
Use Qiskit directly when:
- You're targeting IBM hardware exclusively — Qiskit's transpiler and IBM Runtime primitives give you the best performance on IBM QPUs. HLQuantum's abstraction adds overhead.
- You need fine-grained circuit control — custom gate decompositions, specific transpiler passes, pulse-level control, dynamic circuits with mid-circuit measurements.
- You're doing IBM-ecosystem research — using
qiskit-nature,qiskit-finance,qiskit-optimization, orqiskit-machine-learning— these integrate most deeply with raw Qiskit. - Performance is critical — direct Qiskit code has less overhead than the translation layer in HLQuantum.
- You're contributing to the Qiskit ecosystem — writing Qiskit plugins, tutorials, or research papers where Qiskit is the reference implementation.
When to Use HLQuantum
Use HLQuantum when:
- You need backend flexibility — comparing simulator performance, benchmarking circuits on different architectures, or accessing multiple cloud QPUs.
- You're prototyping algorithms — write once, test everywhere. Don't rewire circuits when switching from local simulation to GPU to real hardware.
- You're teaching or learning — one consistent API across all backends makes learning easier. No need to learn 6 different APIs.
- You want built-in algorithms —
hlq.algorithms.vqe(),hlq.algorithms.qaoa(),hlq.algorithms.grover()handle the boilerplate. - You're building multi-backend applications — if your app needs to run on whatever QPU has the shortest queue or lowest cost, HLQuantum's dispatcher handles that.
Migration: Qiskit → HLQuantum
If you have existing Qiskit code, HLQuantum can consume Qiskit circuits directly:
import hlquantum as hlq
from qiskit import QuantumCircuit
# Existing Qiskit circuit
qc = QuantumCircuit(3)
qc.h(0); qc.cx(0, 1); qc.cx(1, 2)
# Wrap and run on any backend
result = hlq.run(hlq.from_qiskit(qc), backend='pennylane')
result_gpu = hlq.run(hlq.from_qiskit(qc), backend='cudaq')
No rewrite required — you can add HLQuantum's multi-backend capabilities to existing Qiskit code incrementally.
Decision Checklist
Starting a new project?
├── Need IBM-specific features (Qiskit Runtime, pulse control)? → Raw Qiskit
├── Need to run on multiple backends or compare performance? → HLQuantum
├── Learning quantum computing for the first time? → HLQuantum
└── Building a research paper targeting IBM hardware? → Raw Qiskit
Migrating existing Qiskit code?
├── Want to add GPU acceleration? → HLQuantum (from_qiskit + cudaq)
├── Want to try IonQ hardware? → HLQuantum (from_qiskit + ionq)
└── Want to stay IBM-only? → Stay with Qiskit
The two aren't mutually exclusive. Many workflows start with raw Qiskit for circuit design, then wrap with HLQuantum for multi-backend deployment.
Get started: HLQuantum guide · Qiskit SDK guide · Compare all SDKs