IQC 006
· 약 15분
Boolean Functions
| x | ||||
|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 1 |
| 1 | 0 | 1 | 0 | 1 |
- Constant: smae output for all inputs ( and ).
- Balanced: outputs 0 for exactly half, 1 for the other half ( and ).
- In the worst case, need quries to decide which type is exponetial in .
The Quantum Oracle
- Traditional Oracle: black box that computes .
- Query complexity: number of queries to the oracle needed to solve a problem.
- Quantum Oracle: unitary operation that encodes .
- First register: input .
- Second register: auxiliary qubit initialized to or .
- Oracle don't change , but flips if .
- : unchanged.
- : flipped.
- Example:
- .
- if : .
- if :
- so that it ignores the input and only flips the second qubit if .
- it can be reversed: .
Phase Kickback
- Prepare the scratch qubit in .
- if .
- if .
- it doesn't matter where the phase is, it can be moved around:
- .
- if we put the second register to , will be encoded in the phase of the first register.
- The function's output has been "kicked back" into the phase of the first register, while the second register remains unchanged.
The Deutsch Problem
- Given a boolean function , determine if is constant or balanced.
- Constant: same output for all inputs.
- Balanced: outpus 0 for half the inputs and 1 for the other half.
- Prepare .
- Apply to both qubits .
- Apply oracle .
- Phase kickback encodes in the input phase.
- Apply to input qubit, then measure.
- One query to the oracle is sufficient to determine if is constant or balanced.
- if measure 0: is constant.
- if measure 1: is balanced.
Deustch-Jozsa Algorithm
The direct generalization for any -bit boolean function.
- Input register qubits: Initialize qubits in and apply gate to each one.
- Scratch Qubit qubit: Initialize in with and then apply an gate.
- Oracle: Apply to the input and scratch registers (All qubits).
- Final Hadamards: Apply to input qubits.
- Measurement: Measure the input register.
- if all qubits returned : is constant.
- if any qubit returned : is balanced.

How it works
- The initial state is
- After applying gates to the input and scratch registers, we get
- The input register is in a superposition of a computational states containing all possible inputs to -bit string.
- The last qubit hasn't changed from case, so it is in the state .
- The definition of the oracle was generic for any bit string:
- The phase-kickback puts a phase in front of each term in the input register that depends on the output of the function :
- The scratch qubit remains in , so we can ignore it for the rest of the algorithm.
- Constant case
- if is constant, then all the phases are the same, either or :
- The phse in front of every computational state is the same, Either or .
- Before the second application of the gates, the state of the input register is:
- In measurement, in either case, the probability to obtain
- A constant function deterministically returns all zeros with a single query.
- Balanced case
- we are promised the function is either constant or balanced, so there are equal number of and phases. so we don't need to consider this case.
- If the measurement produces anything but all zeros, we know with certainty the function is not constant, so it must be balanced.
- There are a lot of balanced function, but half the terms in the superposition will exactly have a phase.
- It's clearly orthogonal to the state with all ones in superposition.
- Appllying 's will change the state to some other superpostiion, or perhaps a unique computational state.
- But, orthogonality to must remain.
- A balenced function deterministically returns a state with at least one entry as , with a single query.
One quantum query vs classical queries. It is an algorithm that puts all inputs into superposition at once, encodes the function values as phases, and then uses interference to distinguish between constant and balanced functions.
Buildling Oracles
Multi-Controlled and Anti-Controlled Gates
- build that applies to the output qubit exactly when .
- if , the multi-controlled gate is a Toffoli gate.
- is the only input that gives , so we can use a Toffoli gate with controls on the first two qubits and target on the output qubit.
- This is because the Toffoli gate will flip the output qubit if and only if both control qubits are , which corresponds to the input .
- if is the only input that gives , we can use an anti-controlled Toffoli gate, which applies to the target qubit if both control qubits are .
- This is because the anti-controlled Toffoli gate will flip the output qubit if and only if both control qubits are , which corresponds to the input .
- Applying gates to the two control qubits, then applying a Toffoli gate, and then applying gates again to the control qubits will effectively create an anti-controlled Toffoli gate.

- A multi-controlled gates () flips the target only all control qubits are .
- To target a specific input :
- Place gates on each qubit where . (anti-control)
- Apply .
- Undo the gates.
- For qubits, it can be generalized to perform an gate (or any ) with control qubits, requireing extra scratch qubits and Toffoli gates.
- Whenever scratch qubits are invoked, always see a symmetric pattern of gates.

- The computation is done using the scratch qubits.
- The answer is copied to the target or output register
- The computation is inverted to reset the scratch qubits to .
- called "uncomputation", ensures the scratch qubits are returned to their initial state.
- no input or output qubits are entangled with the scratch qubits at the end of the algorithm.
Implementing Deutsch-Jozsa
def random_oracle(n):
# Circuit object to hold the gates
circuit = qiskit.QuantumCircuit(n + 1)
# With 50% probability, return a constant oracle
if np.random.randint(0, 2):
qasm = ""
# another 50:50 chance of it being a 1 instead of 0 oracle
if np.random.randint(0, 2):
qasm += f"x q[{n-1}];"
return qasm, "constant"
# A balanced function has half the inputs as 0
# Randomly select where those are
zero_strings = np.random.choice(range(2**n),int(2**(n-1)),replace=False)
for string in zero_strings:
# Convert base 10 to 2
bitstring= f"{string:0b}"
# X gates for 0 locations
for xi, bit in enumerate(reversed(bitstring)): # enumerate iterates through the list as well as the index in the list
if bit == "1":
circuit.x(xi)
# C^n X gate
circuit.mcx(list(range(n)), n)
# X gates for 0 locations
for xi, bit in enumerate(reversed(bitstring)):
if bit == "1":
circuit.x(xi)
transpiled_circuit = qiskit.transpile(circuit, basis_gates=["u1", "u3", "u2", "cx"])
qasm = qiskit.qasm2.dumps(transpiled_circuit)[47:]
return qasm, "balanced"
OPENQASM 2.0;
qreg q[3];
creg c[2];
x q[2];
h q[0];
h q[1];
h q[2];
/* oracle for f(00)=1 */
x q[0];
x q[1];
ccx q[0],q[1],q[2];
x q[0];
x q[1];
/* oracle for f(11)=1 */
ccx q[0],q[1],q[2];
h q[0];
h q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
OPENQASM 2.0;
qreg q[n+1];
creg c[n];
x q[n];
h q[0];
h q[1];
...
h q[n];
/* oracle U_f */
h q[0];
h q[1];
...
h q[n-1];
measure q[0] -> c[0];
...
measure q[n-1] -> c[n-1];
Bernstein-Vazirani Algorithm
- Given defined as
- where is an unknown -bit string and is the input.
- The goal is to determine the hidden string as few queries as possible.
- Classically: query with input , , ..., to get each bit of .
- Total queries.
- Quantum: use the exact same circuit as Deutsch-Jozsa.
- .
- where we can ignore the output register in the state.
- For , the state after the oracle before the final gate is:
- which is if and if .
- Applying to this state returns :
- .
- The measurement deterministically reveals .
- .
n=2 case
- and
this factorized into:
this reduces the same agument as for each qubit where after the final gates, the state becomes:
Implemnting Bernstein-Vazirani
- if and if .
- To implement , we can use a CNOT from qubit to the scratch qubit if .
import numpy as np
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
def bv_query(n, secret=None):
# Build oracle for f_s(x) = s · x
# q[0]..q[n-1] = input register
# q[n] = scratch/output qubit
if secret is None:
value = np.random.randint(0, 2 ** n)
secret = format(value, f"0{n}b")
else:
secret = secret.zfill(n)
oracle = QuantumCircuit(n + 1, name="Uf")
for index, bit in enumerate(reversed(secret)):
if bit == "1":
oracle.cx(index, n)
return oracle, secret
def bernstein_vazirani_circuit(n, secret=None):
# Build full Bernstein-Vazirani circuit
oracle, secret = bv_query(n, secret)
qc = QuantumCircuit(n + 1, n)
# Prepare scratch qubit in |->
qc.x(n)
# Apply Hadamards to all qubits
for i in range(n + 1):
qc.h(i)
# Apply oracle
qc.compose(oracle, inplace=True)
# Apply final Hadamards to input register
for i in range(n):
qc.h(i)
# Measure input register
for i in range(n):
qc.measure(i, i)
return qc, secret
def run_bernstein_vazirani(n, secret=None, shots=1):
qc, secret = bernstein_vazirani_circuit(n, secret)
simulator = AerSimulator()
compiled = transpile(qc, simulator)
result = simulator.run(compiled, shots=shots).result()
counts = result.get_counts()
measured = max(counts, key=counts.get)
recovered = measured[::-1]
return qc, secret, recovered, counts
# Example
qc, secret, recovered, counts = run_bernstein_vazirani(5, "01101")
print(qc.draw())
print("Secret :", secret)
print("Measured :", recovered)
print("Counts :", counts)
OPENQASM 2.0;
qreg q[6];
creg c[5];
x q[5];
h q[0];
h q[1];
h q[2];
h q[3];
h q[4];
h q[5];
cx q[0],q[5];
cx q[2],q[5];
cx q[3],q[5];
h q[0];
h q[1];
h q[2];
h q[3];
h q[4];
measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];
measure q[3] -> c[3];
measure q[4] -> c[4];
Summary
- There are possible Boolean functions from to .
- A Boolean function is balanced if it outputs 1 on exactly half of the inputs, that is, on out of the possible inputs.
- In Deutsch’s algorithm with , only 1 quantum query is needed to distinguish a constant function from a balanced function.
- A quantum oracle for is defined as the unitary
- Every XOR-based function of the form that depends on at least one input bit is balanced.
- Using multi-controlled gates, together with anti-controls when needed, we can implement an oracle for any Boolean function.
- The phase kickback multiplies the state by the phase factor , so the phase changes exactly when .
- If these questions were stored in a Python list called
questions, then the 8th question would bequestions[7]. - Applying Hadamard gates to qubits initialized in produces an equal superposition over all computational basis states.
- In Deutsch–Jozsa for , measuring all input qubits as 0 means that is constant.
- Bernstein–Vazirani solves the hidden-string problem with 1 quantum query.
- A multi-controlled gate with 3 controls can be implemented using scratch qubits and 4 Toffoli gates.
- Applying followed by yields an oracle whose action on the scratch qubit corresponds to .
- Uncomputation resets scratch qubits to their initial states by applying the inverse of the computation, which means reversing the order of the steps.
- Multi-controlled gates with more than one control can be decomposed into simpler gates, but in general this requires more than just and ; single-qubit gates are also needed.