Quantum vs classical implementation of Deutsch’s Algorithm in Qiskit: same answer, half the queries.
The previous post covered the theory: four Boolean functions, the reversible oracle Uf, the phase-kickback derivation, and the single-query measurement result. This post puts it into running code. We implement the classical two-query approach and the quantum one-query approach side by side in Qiskit so the advantage is visible, not just promised.
Given a black-box function f: {0,1} → {0,1}, determine whether it is constant (f(0) = f(1)) or balanced (f(0) ≠ f(1)).
| Approach | Oracle queries required | Strategy |
|---|---|---|
| Classical | 2 | Evaluate f(0), then f(1), compare |
| Quantum (Deutsch) | 1 | Query in superposition, read phase via interference |
First we build the four oracle circuits. Each implements one of the four single-bit Boolean functions as a reversible quantum gate. The constant oracles ignore x; the balanced oracles use x as a control.
from qiskit_aer import AerSimulator
def create_constant_oracle(constant_value):
“””Creates a constant oracle (returns 0 or 1 for all inputs)”””
oracle = QuantumCircuit(2, name=f”Constant_{constant_value}”)
if constant_value == 1:
oracle.x(1) # Flip the output qubit
return oracle
def create_balanced_oracle(balance_type):
“””Creates a balanced oracle”””
oracle = QuantumCircuit(2, name=f”Balanced_{balance_type}”)
if balance_type == ‘identity’:
# f(x) = x
oracle.cx(0, 1)
elif balance_type == ‘negation’:
# f(x) = NOT x
oracle.x(0)
oracle.cx(0, 1)
oracle.x(0)
return oracle
The classical algorithm calls the oracle twice: once with input 0 to learn f(0), and once with input 1 to learn f(1). Each query is a separate circuit run.
“””First query: Evaluate f(0)”””
qr = QuantumRegister(2, ‘q’)
cr = ClassicalRegister(1, ‘c’)
qc = QuantumCircuit(qr, cr)
# Input: x = 0 (already initialised to |0>)
qc.barrier()
qc.compose(oracle, inplace=True)
qc.barrier()
qc.measure(1, 0) # Measure output to get f(0)
return qc
def classical_deutsch_query2(oracle):
“””Second query: Evaluate f(1)”””
qr = QuantumRegister(2, ‘q’)
cr = ClassicalRegister(1, ‘c’)
qc = QuantumCircuit(qr, cr)
qc.x(0) # Input: x = 1
qc.barrier()
qc.compose(oracle, inplace=True)
qc.barrier()
qc.measure(1, 0) # Measure output to get f(1)
return qc
The quantum circuit initialises q[1] = |1⟩, applies Hadamard gates to both wires, queries the oracle exactly once, then applies a final Hadamard to q[0] before measuring it. The oracle is never called again.
“””Implements Deutsch’s algorithm — requires only ONE query”””
qr = QuantumRegister(2, ‘q’)
cr = ClassicalRegister(1, ‘c’)
qc = QuantumCircuit(qr, cr)
# Step 1: Initialise q[1] to |1>
qc.x(1)
qc.barrier()
# Step 2: Hadamard on both wires (superposition)
qc.h(0)
qc.h(1)
qc.barrier()
# Step 3: Single oracle query
qc.compose(oracle, inplace=True)
qc.barrier()
# Step 4: Final Hadamard on q[0]
qc.h(0)
qc.barrier()
# Step 5: Measure q[0] — the INPUT qubit, not the output
qc.measure(0, 0)
return qc
The quantum circuit measures q[0], the input qubit. The classical circuits measure q[1], the output qubit. That structural difference is the entire quantum advantage: the quantum algorithm reads a global property of the function via interference, not an individual function value.
Test all four oracles with both approaches and compare query counts.
(“Constant 0”, create_constant_oracle(0)),
(“Constant 1”, create_constant_oracle(1)),
(“Balanced (Identity)”, create_balanced_oracle(‘identity’)),
(“Balanced (Negation)”, create_balanced_oracle(‘negation’))
]
simulator = AerSimulator()
for name, oracle in oracles:
# Classical: 2 queries
f_0 = int(list(simulator.run(classical_deutsch_query1(oracle), shots=1).result().get_counts().keys())[0])
f_1 = int(list(simulator.run(classical_deutsch_query2(oracle), shots=1).result().get_counts().keys())[0])
classical_result = “CONSTANT” if f_0 == f_1 else “BALANCED”
# Quantum: 1 query
counts = simulator.run(deutsch_algorithm(oracle), shots=1000).result().get_counts()
quantum_result = “CONSTANT” if ‘0’ in counts else “BALANCED”
print(f”{name}: Classical={classical_result}, Quantum={quantum_result}”)
Sample output:
Constant 1: Classical=CONSTANT, Quantum=CONSTANT
Balanced (Identity): Classical=BALANCED, Quantum=BALANCED
Balanced (Negation): Classical=BALANCED, Quantum=BALANCED
Classical Query 1 — Evaluate f(0)
q[0] stays in |0⟩, both wires pass through Uf, and q[1] is measured to read f(0).
Classical Query 2 — Evaluate f(1)
An X gate flips q[0] to |1⟩, both wires pass through Uf, and q[1] is measured to read f(1).
Quantum Deutsch — Single Query
H gates create superposition on both wires, one oracle query encodes f(0) ⊕ f(1) as a phase, the final H on q[0] converts phase to amplitude, and measuring q[0] gives the answer directly.
The measurement result on q[0] maps directly to the function type:
| Measure q[0] | Function type | Interference mechanism |
|---|---|---|
| 0 | Constant | f(0) ⊕ f(1) = 0 → constructive on |0⟩ |
| 1 | Balanced | f(0) ⊕ f(1) = 1 → destructive on |0⟩, constructive on |1⟩ |
The quantum speedup is 2x here (one query instead of two). Modest for a two-input function, but the same technique scales: Deutsch-Jozsa extends this to n-bit functions, cutting 2n−1+1 classical queries down to one. Simon’s algorithm extends it further. Shor’s algorithm for factoring, the most consequential quantum algorithm known, relies on the same architectural idea: query in superposition, encode information as phase, extract via interference and measurement.
pip install qiskit qiskit-aer. The full comparison script outputs all four oracle types side by side. Try modifying the oracle functions to explore how each gate sequence implements f.
Quantum Series 2026 · Built with Qiskit 1.x
✦ This article was generated with the assistance of Claude by Anthropic ✦
Share this:
- Share on X (Opens in new window) X
- Share on Facebook (Opens in new window) Facebook
- Print (Opens in new window) Print
- Email a link to a friend (Opens in new window) Email
- Share on LinkedIn (Opens in new window) LinkedIn
- Share on Reddit (Opens in new window) Reddit
- Share on Tumblr (Opens in new window) Tumblr
- Share on Threads (Opens in new window) Threads
- Share on Pinterest (Opens in new window) Pinterest
- Share on Telegram (Opens in new window) Telegram
- Share on WhatsApp (Opens in new window) WhatsApp
- Share on Bluesky (Opens in new window) Bluesky
One thought on “Deutsch Algorithm Revisited: Quantum vs Classical Implementation in Qiskit”