Построить и различить оракулы Дойча–Йожи
Обещано, что булева функция либо постоянна, либо сбалансирована: в последнем случае половина входов даёт 0, половина 1. Оракул действует как $|x,y\rangle\mapsto|x,y\oplus f(x)\rangle$. В алгоритме вход готовится в равномерной суперпозиции, выход — в $|-\rangle$; после оракула ко всем входам снова применяется H, затем они измеряются. Постоянная функция даёт 0000, сбалансированная — никогда 0000.
1. Можете ли вы построить сбалансированный или постоянный оракул другой формы?
2. Функция dj_problem_oracle ниже возвращает оракул для n=4 как вентиль на пяти кубитах; последний q4 — выход. Оригинал предлагает разные целые аргументы от 1 до 5. Используйте алгоритм Дойча–Йожи, чтобы определить для каждого оракула, постоянный он или сбалансированный. Автор настоятельно рекомендует aer_simulator вместо реального устройства.
Восстановленная официальная функция сохранена полностью. Оговорка версии: в ней явно определены варианты 1–4; для аргумента 5 выполняется ветка else и возвращается пустая схема. Рисунок — пример полной схемы до задания.
Original complete simulator examples:
# initialization
import numpy as np
# importing Qiskit
from qiskit import IBMQ, Aer
from qiskit.providers.ibmq import least_busy
from qiskit import QuantumCircuit, transpile
# import basic plot tools
from qiskit.visualization import plot_histogram
# set the length of the n-bit input string.
n = 3
# set the length of the n-bit input string.
n = 3
const_oracle = QuantumCircuit(n+1)
output = np.random.randint(2)
if output == 1:
const_oracle.x(n)
const_oracle.draw()
balanced_oracle = QuantumCircuit(n+1)
b_str = "101"
# Place X-gates
for qubit in range(len(b_str)):
if b_str[qubit] == '1':
balanced_oracle.x(qubit)
# Use barrier as divider
balanced_oracle.barrier()
# Controlled-NOT gates
for qubit in range(n):
balanced_oracle.cx(qubit, n)
balanced_oracle.barrier()
# Place X-gates
for qubit in range(len(b_str)):
if b_str[qubit] == '1':
balanced_oracle.x(qubit)
# Show oracle
balanced_oracle.draw()
dj_circuit = QuantumCircuit(n+1, n)
# Apply H-gates
for qubit in range(n):
dj_circuit.h(qubit)
# Put qubit in state |->
dj_circuit.x(n)
dj_circuit.h(n)
# Add oracle
dj_circuit = dj_circuit.compose(balanced_oracle)
# Repeat H-gates
for qubit in range(n):
dj_circuit.h(qubit)
dj_circuit.barrier()
# Measure
for i in range(n):
dj_circuit.measure(i, i)
# Display circuit
dj_circuit.draw()
# use local simulator
aer_sim = Aer.get_backend('aer_simulator')
results = aer_sim.run(dj_circuit).result()
answer = results.get_counts()
plot_histogram(answer)
def dj_oracle(case, n):
# We need to make a QuantumCircuit object to return
# This circuit has n+1 qubits: the size of the input,
# plus one output qubit
oracle_qc = QuantumCircuit(n+1)
# First, let's deal with the case in which oracle is balanced
if case == "balanced":
# First generate a random number that tells us which CNOTs to
# wrap in X-gates:
b = np.random.randint(1,2**n)
# Next, format 'b' as a binary string of length 'n', padded with zeros:
b_str = format(b, '0'+str(n)+'b')
# Next, we place the first X-gates. Each digit in our binary string
# corresponds to a qubit, if the digit is 0, we do nothing, if it's 1
# we apply an X-gate to that qubit:
for qubit in range(len(b_str)):
if b_str[qubit] == '1':
oracle_qc.x(qubit)
# Do the controlled-NOT gates for each qubit, using the output qubit
# as the target:
for qubit in range(n):
oracle_qc.cx(qubit, n)
# Next, place the final X-gates
for qubit in range(len(b_str)):
if b_str[qubit] == '1':
oracle_qc.x(qubit)
# Case in which oracle is constant
if case == "constant":
# First decide what the fixed output of the oracle will be
# (either always 0 or always 1)
output = np.random.randint(2)
if output == 1:
oracle_qc.x(n)
oracle_gate = oracle_qc.to_gate()
oracle_gate.name = "Oracle" # To show when we display the circuit
return oracle_gate
def dj_algorithm(oracle, n):
dj_circuit = QuantumCircuit(n+1, n)
# Set up the output qubit:
dj_circuit.x(n)
dj_circuit.h(n)
# And set up the input register:
for qubit in range(n):
dj_circuit.h(qubit)
# Let's append the oracle gate to our circuit:
dj_circuit.append(oracle, range(n+1))
# Finally, perform the H-gates again and measure:
for qubit in range(n):
dj_circuit.h(qubit)
for i in range(n):
dj_circuit.measure(i, i)
return dj_circuit
n = 4
oracle_gate = dj_oracle('balanced', n)
dj_circuit = dj_algorithm(oracle_gate, n)
dj_circuit.draw()
transpiled_dj_circuit = transpile(dj_circuit, aer_sim)
results = aer_sim.run(transpiled_dj_circuit).result()
answer = results.get_counts()
plot_histogram(answer)
from qiskit_textbook.problems import dj_problem_oracle
oracle = dj_problem_oracle(1)Recovered original dj_problem_oracle:
from qiskit import QuantumCircuit
def dj_problem_oracle(problem, to_gate=True):
"""Returns a 5-qubit Deutsch-Joza Oracle"""
qc = QuantumCircuit(5)
int(problem)
if problem == 1:
for q in range(4):
qc.cx(q, 4)
elif problem == 2:
qc.cx(0, 4)
qc.cx(0, 4)
elif problem == 3:
qc.ccx(0,2,4)
qc.ccx(1,2,4)
for q in range(3):
qc.x(q)
qc.ccx(0,2,4)
qc.ccx(1,3,4)
elif problem == 4:
qc.cx(2,4)
else:
print("There are only currently 4 oracles in this problem set, returning empty (balanced) gate")
if to_gate:
return qc.to_gate()
else:
return qc