The Deutsch–Jozsa algorithm is a deterministic quantum algorithm proposed by David Deutsch and Richard Jozsa in 1992 with improvements by Richard Cleve, Artur Ekert, Chiara Macchiavello, and Michele Mosca in 1998.[1] [2] Although of little practical use, it is one of the first examples of a quantum algorithm that is exponentially faster than any possible deterministic classical algorithm.[3]
The Deutsch–Jozsa problem is specifically designed to be easy for a quantum algorithm and hard for any deterministic classical algorithm. It is a black box problem that can be solved efficiently by a quantum computer with no error, whereas a deterministic classical computer would need an exponential number of queries to the black box to solve the problem. More formally, it yields an oracle relative to which EQP, the class of problems that can be solved exactly in polynomial time on a quantum computer, and P are different.[4]
Since the problem is easy to solve on a probabilistic classical computer, it does not yield an oracle separation with BPP, the class of problems that can be solved with bounded error in polynomial time on a probabilistic classical computer. Simon's problem is an example of a problem that yields an oracle separation between BQP and BPP.
In the Deutsch–Jozsa problem, we are given a black box quantum computer known as an oracle that implements some function:
f\colon\{0,1\}n → \{0,1\}
The function takes n-bit binary values as input and produces either a 0 or a 1 as output for each such value. We are promised that the function is either constant (0 on all inputs or 1 on all inputs) or balanced (1 for exactly half of the input domain and 0 for the other half). The task then is to determine if
f
For a conventional deterministic algorithm where
n
2n-1+1
f
f
k
\epsilon\leq1/2k
k\geq1
k=2n-1+1
f
The Deutsch–Jozsa algorithm generalizes earlier (1985) work by David Deutsch, which provided a solution for the simple case where
n=1
f:\{0,1\} → \{0,1\}
The algorithm, as Deutsch had originally proposed it, was not deterministic. The algorithm was successful with a probability of one half. In 1992, Deutsch and Jozsa produced a deterministic algorithm which was generalized to a function which takes
n
Further improvements to the Deutsch–Jozsa algorithm were made by Cleve et al., resulting in an algorithm that is both deterministic and requires only a single query of
f
For the Deutsch–Jozsa algorithm to work, the oracle computing
f(x)
x
x
x
f
The algorithm begins with the
n+1
|0\rangle ⊗ |1\rangle
|0\rangle
|1\rangle
1 | |
\sqrt{2n+1 |
where
x
n
0
2n-1
f
|x\rangle|y\rangle
|x\rangle|y ⊕ f(x)\rangle
⊕
1 | |
\sqrt{2n+1 |
For each
x,f(x)
1 | |
\sqrt{2n+1 |
At this point the last qubit
|0\rangle-|1\rangle | |
\sqrt{2 |
1 | |
\sqrt{2n |
Next, we will have each qubit go through a Hadamard gate. The total transformation over all
n
H ⊗ |k\rangle=
1 | |
\sqrt{2n |
(
j ⋅ k=j0k0 ⊕ j1k1 ⊕ … ⊕ jn-1kn-1
1 | |
\sqrt{2n |
From this, we can see that the probability for a state
k
\left| | 1 |
2n |
2n-1 | |
\sum | |
x=0 |
(-1)f(x)(-1)x ⋅ \right|2
The probability of measuring
k=0
|0\rangle ⊗
| | 1 |
2n |
2n-1 | |
\sum | |
x=0 |
(-1)f(x)|2
which evaluates to 1 if
f(x)
f(x)
|0\rangle ⊗
f(x)
f(x)
Deutsch's algorithm is a special case of the general Deutsch–Jozsa algorithm where n = 1 in
f\colon\{0,1\}n → \{0,1\}
f(0)=f(1)
f(0) ⊕ f(1)
⊕
f
f
We begin with the two-qubit state
|0\rangle|1\rangle
1 | |
2 |
(|0\rangle+|1\rangle)(|0\rangle-|1\rangle).
We are given a quantum implementation of the function
f
|x\rangle|y\rangle
|x\rangle|f(x) ⊕ y\rangle
1 | |
2 |
(|0\rangle(|f(0) ⊕ 0\rangle-|f(0) ⊕ 1\rangle)+|1\rangle(|f(1) ⊕ 0\rangle-|f(1) ⊕ 1\rangle))
= | 1 |
2 |
((-1)f(0)|0\rangle(|0\rangle-|1\rangle)+(-1)f(1)|1\rangle(|0\rangle-|1\rangle))
=(-1)f(0)
1 | |
2 |
\left(|0\rangle+(-1)f(0) ⊕ |1\rangle\right)(|0\rangle-|1\rangle).
We ignore the last bit and the global phase and therefore have the state
1 | |
\sqrt2 |
(|0\rangle+(-1)f(0) ⊕ |1\rangle).
Applying a Hadamard gate to this state we have
1 | |
2 |
(|0\rangle+|1\rangle+(-1)f(0) ⊕ |0\rangle-(-1)f(0) ⊕ |1\rangle)
= | 1 |
2 |
((1+(-1)f(0) ⊕ )|0\rangle+(1-(-1)f(0) ⊕ )|1\rangle).
f(0) ⊕ f(1)=0
|0\rangle
f(0) ⊕ f(1)=1
|1\rangle
f(x)
Below is a simple example of how the Deutsch–Jozsa algorithm can be implemented in Python using Qiskit, an open-source quantum computing software development framework by IBM. We will walk through each part of the code step by step to show how it translates the theory into a working quantum circuit.
If `output` is 0, the oracle always returns 0. If `output` is 1, the oracle always returns 1.
Args: n_qubits (int): The number of input qubits. output (int): The constant output value of the function (0 or 1).
Returns: QuantumCircuit: A quantum circuit implementing the constant oracle. """ oracle = QuantumCircuit(n_qubits + 1)
# If the oracle should always output 1, we flip the "output" qubit # using an X-gate (think of it as a NOT gate on a qubit). if output
return oracle
def create_balanced_oracle(n_qubits): """ Creates a 'balanced' oracle.
Half of the input bit patterns output 0, and the other half output 1.
For demonstration, this function implements a simple balanced function by placing X-gates on the first qubit of the input as a control, inverting the output qubit for half of the inputs.
Args: n_qubits (int): The number of input qubits.
Returns: QuantumCircuit: A quantum circuit implementing the balanced oracle. """ oracle = QuantumCircuit(n_qubits + 1)
# We'll use a simple pattern: if the first qubit is 1, flip the output. # This means for half of the possible inputs, the output changes. oracle.cx(0, n_qubits)
return oracle
The circuit performs the following steps: 1. Start all 'input' qubits in |0>. 2. Start the 'output' qubit in |1>. 3. Apply Hadamard gates to all qubits. 4. Apply the oracle. 5. Apply Hadamard gates again to the input qubits. 6. Measure the input qubits.
Args: oracle (QuantumCircuit): The circuit encoding the 'mystery' function f(x). n_qubits (int): The number of input qubits.
Returns: QuantumCircuit: The complete Deutsch-Jozsa circuit ready to run. """ # Total of n_qubits for input, plus 1 for the output qubit dj_circuit = QuantumCircuit(n_qubits + 1, n_qubits)
# 1. The input qubits are already set to |0>. # 2. The output qubit is set to |1>. We achieve this by an X gate. dj_circuit.x(n_qubits)
# 3. Apply Hadamard gates to all qubits (input + output). for qubit in range(n_qubits + 1): dj_circuit.h(qubit)
# 4. Append the oracle circuit. dj_circuit.compose(oracle, inplace=True)
# 5. Apply Hadamard gates again to the input qubits ONLY. for qubit in range(n_qubits): dj_circuit.h(qubit)
# 6. Finally, measure the input qubits. for qubit in range(n_qubits): dj_circuit.measure(qubit, qubit)
return dj_circuit
Args: n_qubits (int): Number of input qubits. oracle_type (str): Specifies the type of oracle, either 'constant' or 'balanced'. constant_output (int): If the oracle is constant, determines whether it returns 0 or 1. """ # Create the chosen oracle if oracle_type
# Create the Deutsch-Jozsa circuit dj_circ = deutsch_jozsa_circuit(oracle, n_qubits)
# Draw the circuit for visual reference display(dj_circ.draw)
# Use the simulator backend to run the circuit simulator = Aer.get_backend('aer_simulator') transpiled_circ = transpile(dj_circ, simulator) job = simulator.run(transpiled_circ, shots=1) result = job.result counts = result.get_counts(transpiled_circ)
print("Measurement outcomes:", counts)
# Interpret the measurement # If all measured bits are 0 (e.g., '000' for 3 qubits), then the # function is constant. Otherwise, it is balanced. measured_result = max(counts, key=counts.get) # The most likely outcome if measured_result
run_deutsch_jozsa_test(n_qubits=3, oracle_type='constant', constant_output=0)
print("\n" + "="*50 + "\n")
run_deutsch_jozsa_test(n_qubits=3, oracle_type='balanced')
Using a CONSTANT oracle that always returns 0 ┌───┐┌───┐┌─┐ q_0: ┤ H ├┤ H ├┤M├────── ├───┤├───┤└╥┘┌─┐ q_1: ┤ H ├┤ H ├─╫─┤M├─── ├───┤├───┤ ║ └╥┘┌─┐ q_2: ┤ H ├┤ H ├─╫──╫─┤M├ ├───┤├───┤ ║ ║ └╥┘ q_3: ┤ X ├┤ H ├─╫──╫──╫─ └───┘└───┘ ║ ║ ║ c: 3/═══════════╩══╩══╩═ 0 1 2 Measurement outcomes: {'000': 1} Conclusion: f(x) is CONSTANT. ================================================== Using a BALANCED oracle. ┌───┐ ┌───┐ ┌─┐ q_0: ┤ H ├───────■──┤ H ├───┤M├ ├───┤┌───┐ │ └┬─┬┘ └╥┘ q_1: ┤ H ├┤ H ├──┼───┤M├─────╫─ ├───┤├───┤ │ └╥┘ ┌─┐ ║ q_2: ┤ H ├┤ H ├──┼────╫──┤M├─╫─ ├───┤├───┤┌─┴─┐ ║ └╥┘ ║ q_3: ┤ X ├┤ H ├┤ X ├──╫───╫──╫─ └───┘└───┘└───┘ ║ ║ ║ c: 3/═════════════════╩═══╩══╩═ 1 2 0 Measurement outcomes: {'001': 1} Conclusion: f(x) is BALANCED.
We use Qiskit’s core elements:
QuantumCircuit
to build quantum circuitsAer
, transpile
and run
to run our circuit on a classical simulatorCNOT
gate (cx
), which flips the output qubit when the first input qubit is 1.\vert0\rangle
\vert1\rangle
dj_circuit.h(qubit)
) to all qubits. Recall that the Hadamard gate spreads the amplitudes “evenly” between\vert0\rangle
\vert1\rangle
\vert0...0\rangle
We run the circuit using Aer’s built-in https://qiskit.github.io/qiskit-aer/<code>aer_simulator</code>. Because the Deutsch–Jozsa algorithm only needs one execution (one set of shots) to distinguish between constant and balanced with 100% certainty, running multiple shots will always yield the same outcome.
Classically, you might have to “call” the function (f) (our “mystery” black box) many times—potentially up to
2n-1+1